aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp55
-rw-r--r--Cargo.lock446
-rw-r--r--Cargo.toml80
-rw-r--r--Cargo.toml.orig53
-rw-r--r--METADATA14
-rw-r--r--OWNERS2
-rw-r--r--README.md83
-rw-r--r--TEST_MAPPING14
-rw-r--r--android/bindgen_cmd/Android.bp1
-rw-r--r--android/bindgen_cmd/src/lib.rs6
-rw-r--r--build.rs83
-rw-r--r--callbacks.rs (renamed from src/callbacks.rs)65
-rw-r--r--cargo2android.json4
-rw-r--r--clang.rs (renamed from src/clang.rs)209
-rw-r--r--[-rwxr-xr-x]codegen/bitfield_unit.rs (renamed from src/codegen/bitfield_unit.rs)0
-rw-r--r--codegen/bitfield_unit_tests.rs (renamed from src/codegen/bitfield_unit_tests.rs)0
-rw-r--r--codegen/dyngen.rs (renamed from src/codegen/dyngen.rs)43
-rw-r--r--codegen/error.rs (renamed from src/codegen/error.rs)0
-rw-r--r--codegen/helpers.rs (renamed from src/codegen/helpers.rs)26
-rw-r--r--codegen/impl_debug.rs (renamed from src/codegen/impl_debug.rs)0
-rw-r--r--codegen/impl_partialeq.rs (renamed from src/codegen/impl_partialeq.rs)0
-rw-r--r--codegen/mod.rs (renamed from src/codegen/mod.rs)994
-rw-r--r--codegen/postprocessing/merge_extern_blocks.rs66
-rw-r--r--codegen/postprocessing/mod.rs66
-rw-r--r--codegen/postprocessing/sort_semantically.rs38
-rw-r--r--codegen/serialize.rs356
-rw-r--r--codegen/struct_layout.rs (renamed from src/codegen/struct_layout.rs)10
-rw-r--r--csmith-fuzzing/README.md65
-rw-r--r--deps.rs (renamed from src/deps.rs)2
-rw-r--r--extra_assertions.rs (renamed from src/extra_assertions.rs)0
-rw-r--r--features.rs (renamed from src/features.rs)43
-rw-r--r--ir/analysis/derive.rs (renamed from src/ir/analysis/derive.rs)10
-rw-r--r--ir/analysis/has_destructor.rs (renamed from src/ir/analysis/has_destructor.rs)0
-rw-r--r--ir/analysis/has_float.rs (renamed from src/ir/analysis/has_float.rs)0
-rw-r--r--ir/analysis/has_type_param_in_array.rs (renamed from src/ir/analysis/has_type_param_in_array.rs)0
-rw-r--r--ir/analysis/has_vtable.rs (renamed from src/ir/analysis/has_vtable.rs)0
-rw-r--r--ir/analysis/mod.rs (renamed from src/ir/analysis/mod.rs)16
-rw-r--r--ir/analysis/sizedness.rs (renamed from src/ir/analysis/sizedness.rs)0
-rw-r--r--ir/analysis/template_params.rs (renamed from src/ir/analysis/template_params.rs)5
-rw-r--r--ir/annotations.rs (renamed from src/ir/annotations.rs)4
-rw-r--r--ir/comment.rs (renamed from src/ir/comment.rs)51
-rw-r--r--ir/comp.rs (renamed from src/ir/comp.rs)80
-rw-r--r--ir/context.rs (renamed from src/ir/context.rs)350
-rw-r--r--ir/derive.rs (renamed from src/ir/derive.rs)0
-rw-r--r--ir/dot.rs (renamed from src/ir/dot.rs)0
-rw-r--r--ir/enum_ty.rs (renamed from src/ir/enum_ty.rs)33
-rw-r--r--ir/function.rs (renamed from src/ir/function.rs)233
-rw-r--r--ir/int.rs (renamed from src/ir/int.rs)0
-rw-r--r--ir/item.rs (renamed from src/ir/item.rs)45
-rw-r--r--ir/item_kind.rs (renamed from src/ir/item_kind.rs)0
-rw-r--r--ir/layout.rs (renamed from src/ir/layout.rs)4
-rw-r--r--ir/mod.rs (renamed from src/ir/mod.rs)0
-rw-r--r--ir/module.rs (renamed from src/ir/module.rs)0
-rw-r--r--ir/objc.rs (renamed from src/ir/objc.rs)13
-rw-r--r--ir/template.rs (renamed from src/ir/template.rs)1
-rw-r--r--ir/traversal.rs (renamed from src/ir/traversal.rs)58
-rw-r--r--ir/ty.rs (renamed from src/ir/ty.rs)78
-rw-r--r--ir/var.rs (renamed from src/ir/var.rs)132
-rw-r--r--lib.rs (renamed from src/lib.rs)1299
-rw-r--r--log_stubs.rs (renamed from src/log_stubs.rs)0
-rw-r--r--out/tests.rs0
-rw-r--r--parse.rs40
-rw-r--r--patches/Android.bp.diff13
-rw-r--r--patches/bindgen_cmd.diff90
-rwxr-xr-xpost_update.sh9
-rw-r--r--regex_set.rs (renamed from src/regex_set.rs)17
-rw-r--r--src/main.rs113
-rw-r--r--src/options.rs1000
-rw-r--r--src/parse.rs102
-rw-r--r--time.rs (renamed from src/time.rs)0
71 files changed, 3256 insertions, 3371 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index f1c8552..32c33e6 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "89032649044d875983a851fff6fbde2d4e2ceaeb"
- }
-}
+ "sha1": "ae6817256ac557981906e93a1f866349db85053e"
+ },
+ "path_in_vcs": "bindgen"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 9166c33..86a6c71 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,70 +35,30 @@ genrule {
name: "copy_bindgen_build_out",
srcs: ["out/*"],
cmd: "cp $(in) $(genDir)",
- out: [
- "host-target.txt",
- "tests.rs",
- ],
-}
-
-rust_binary_host {
- name: "bindgen",
- // has rustc warnings
- crate_name: "bindgen",
- cargo_env_compat: true,
- cargo_pkg_version: "0.59.2",
- srcs: [
- "src/main.rs",
- ":copy_bindgen_build_out",
- ],
- edition: "2018",
- features: [
- "clap",
- "runtime",
- "which",
- "which-rustfmt",
- ],
- rustlibs: [
- "libbindgen",
- "libbitflags",
- "libcexpr",
- "libclang_sys",
- "libclap",
- "liblazy_static",
- "liblazycell",
- "libpeeking_take_while",
- "libproc_macro2",
- "libquote",
- "libregex",
- "librustc_hash",
- "libshlex",
- "libwhich",
- ],
- compile_multilib: "first",
+ out: ["host-target.txt"],
}
rust_library_host {
name: "libbindgen",
- // has rustc warnings
crate_name: "bindgen",
cargo_env_compat: true,
- cargo_pkg_version: "0.59.2",
+ cargo_pkg_version: "0.64.0",
srcs: [
- "src/lib.rs",
+ "lib.rs",
":copy_bindgen_build_out",
],
edition: "2018",
features: [
- "clap",
+ "cli",
+ "experimental",
"runtime",
"which",
"which-rustfmt",
],
rustlibs: [
- "libbitflags",
+ "libbitflags-1.3.2",
"libcexpr",
"libclang_sys",
- "libclap",
"liblazy_static",
"liblazycell",
"libpeeking_take_while",
@@ -107,7 +67,10 @@ rust_library_host {
"libregex",
"librustc_hash",
"libshlex",
+ "libsyn",
"libwhich",
],
compile_multilib: "first",
+ product_available: true,
+ vendor_available: true,
}
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index d79a408..0000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,446 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "aho-corasick"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "ansi_term"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "bindgen"
-version = "0.59.2"
-dependencies = [
- "bitflags",
- "cexpr",
- "clang-sys",
- "clap",
- "diff",
- "env_logger",
- "lazy_static",
- "lazycell",
- "log",
- "peeking_take_while",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "tempfile",
- "which",
-]
-
-[[package]]
-name = "bitflags"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "clang-sys"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
-[[package]]
-name = "clap"
-version = "2.33.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
-dependencies = [
- "ansi_term",
- "atty",
- "bitflags",
- "strsim",
- "textwrap",
- "unicode-width",
- "vec_map",
-]
-
-[[package]]
-name = "diff"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
-
-[[package]]
-name = "either"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
-
-[[package]]
-name = "env_logger"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
-dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "glob"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
-
-[[package]]
-name = "hermit-abi"
-version = "0.1.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
-[[package]]
-name = "libc"
-version = "0.2.98"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
-
-[[package]]
-name = "libloading"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
-dependencies = [
- "cfg-if",
- "winapi",
-]
-
-[[package]]
-name = "log"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "memchr"
-version = "2.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
-
-[[package]]
-name = "minimal-lexical"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677"
-
-[[package]]
-name = "nom"
-version = "7.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1"
-dependencies = [
- "memchr",
- "minimal-lexical",
- "version_check",
-]
-
-[[package]]
-name = "peeking_take_while"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "regex"
-version = "1.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
-[[package]]
-name = "shlex"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
-
-[[package]]
-name = "strsim"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-
-[[package]]
-name = "tempfile"
-version = "3.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
-dependencies = [
- "cfg-if",
- "libc",
- "rand",
- "redox_syscall",
- "remove_dir_all",
- "winapi",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
-name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "unicode-width"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
-name = "vec_map"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
-
-[[package]]
-name = "version_check"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
-
-[[package]]
-name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
-
-[[package]]
-name = "which"
-version = "4.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cc009ab82a2afc94b9e467ab4214aee9cad1356cd9191264203d7d72006e00d"
-dependencies = [
- "either",
- "lazy_static",
- "libc",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-util"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
index 8b8853a..15868cd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,28 +11,36 @@
[package]
edition = "2018"
+rust-version = "1.60.0"
name = "bindgen"
-version = "0.59.2"
-authors = ["Jyun-Yan You <jyyou.tw@gmail.com>", "Emilio Cobos Álvarez <emilio@crisal.io>", "Nick Fitzgerald <fitzgen@gmail.com>", "The Servo project developers"]
+version = "0.64.0"
+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"
-include = ["LICENSE", "README.md", "Cargo.toml", "build.rs", "src/*.rs", "src/**/*.rs"]
description = "Automatically generates Rust FFI bindings to C and C++ libraries."
homepage = "https://rust-lang.github.io/rust-bindgen/"
documentation = "https://docs.rs/bindgen"
-readme = "README.md"
-keywords = ["bindings", "ffi", "code-generation"]
-categories = ["external-ffi-bindings", "development-tools::ffi"]
+readme = "../README.md"
+keywords = [
+ "bindings",
+ "ffi",
+ "code-generation",
+]
+categories = [
+ "external-ffi-bindings",
+ "development-tools::ffi",
+]
license = "BSD-3-Clause"
repository = "https://github.com/rust-lang/rust-bindgen"
[lib]
-path = "src/lib.rs"
-
-[[bin]]
name = "bindgen"
-path = "src/main.rs"
-doc = false
-required-features = ["clap"]
+path = "./lib.rs"
+
[dependencies.bitflags]
version = "1.0.3"
@@ -43,14 +51,6 @@ version = "0.6"
version = "1"
features = ["clang_6_0"]
-[dependencies.clap]
-version = "2"
-optional = true
-
-[dependencies.env_logger]
-version = "0.9.0"
-optional = true
-
[dependencies.lazy_static]
version = "1"
@@ -73,8 +73,11 @@ version = "1"
default-features = false
[dependencies.regex]
-version = "1.0"
-features = ["std", "unicode"]
+version = "1.5"
+features = [
+ "std",
+ "unicode",
+]
default-features = false
[dependencies.rustc-hash]
@@ -83,33 +86,32 @@ version = "1.0.1"
[dependencies.shlex]
version = "1"
+[dependencies.syn]
+version = "1.0.99"
+features = [
+ "full",
+ "extra-traits",
+ "visit-mut",
+]
+
[dependencies.which]
version = "4.2.1"
optional = true
default-features = false
-[dev-dependencies.clap]
-version = "2"
-
-[dev-dependencies.diff]
-version = "0.1"
-
-[dev-dependencies.shlex]
-version = "1"
-
-[dev-dependencies.tempfile]
-version = "3"
[features]
-default = ["logging", "clap", "runtime", "which-rustfmt"]
-logging = ["env_logger", "log"]
+cli = []
+default = [
+ "logging",
+ "runtime",
+ "which-rustfmt",
+]
+experimental = []
+logging = ["log"]
runtime = ["clang-sys/runtime"]
static = ["clang-sys/static"]
testing_only_docs = []
testing_only_extra_assertions = []
-testing_only_libclang_3_9 = []
-testing_only_libclang_4 = []
testing_only_libclang_5 = []
testing_only_libclang_9 = []
which-rustfmt = ["which"]
-[badges.travis-ci]
-repository = "rust-lang/rust-bindgen"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ba41a22..bc53be5 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -10,72 +10,45 @@ keywords = ["bindings", "ffi", "code-generation"]
categories = ["external-ffi-bindings", "development-tools::ffi"]
license = "BSD-3-Clause"
name = "bindgen"
-readme = "README.md"
+readme = "../README.md"
repository = "https://github.com/rust-lang/rust-bindgen"
documentation = "https://docs.rs/bindgen"
homepage = "https://rust-lang.github.io/rust-bindgen/"
-version = "0.59.2"
+version = "0.64.0"
edition = "2018"
build = "build.rs"
-
-include = [
- "LICENSE",
- "README.md",
- "Cargo.toml",
- "build.rs",
- "src/*.rs",
- "src/**/*.rs",
-]
-
-[badges]
-travis-ci = { repository = "rust-lang/rust-bindgen" }
+# If you change this, also update README.md and msrv in .github/workflows/bindgen.yml
+rust-version = "1.60.0"
[lib]
-path = "src/lib.rs"
-
-[[bin]]
name = "bindgen"
-path = "src/main.rs"
-doc = false
-required-features = ["clap"]
-
-[dev-dependencies]
-diff = "0.1"
-clap = "2"
-shlex = "1"
-tempfile = "3"
+path = "./lib.rs"
[dependencies]
bitflags = "1.0.3"
cexpr = "0.6"
-# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
-clap = { version = "2", optional = true }
clang-sys = { version = "1", features = ["clang_6_0"] }
lazycell = "1"
lazy_static = "1"
peeking_take_while = "0.1.2"
quote = { version = "1", default-features = false }
-regex = { version = "1.0", default-features = false , features = [ "std", "unicode"]}
+syn = { version = "1.0.99", features = ["full", "extra-traits", "visit-mut"]}
+regex = { version = "1.5", default-features = false , features = ["std", "unicode"] }
which = { version = "4.2.1", optional = true, default-features = false }
shlex = "1"
rustc-hash = "1.0.1"
proc-macro2 = { version = "1", default-features = false }
-
-[dependencies.env_logger]
-optional = true
-version = "0.9.0"
-
-[dependencies.log]
-optional = true
-version = "0.4"
+log = { version = "0.4", optional = true }
[features]
-default = ["logging", "clap", "runtime", "which-rustfmt"]
-logging = ["env_logger", "log"]
+default = ["logging", "runtime", "which-rustfmt"]
+logging = ["log"]
static = ["clang-sys/static"]
runtime = ["clang-sys/runtime"]
# Dynamically discover a `rustfmt` binary using the `which` crate
which-rustfmt = ["which"]
+cli = []
+experimental = []
# These features only exist for CI testing -- don't use them if you're not hacking
# on bindgen!
@@ -83,5 +56,3 @@ testing_only_docs = []
testing_only_extra_assertions = []
testing_only_libclang_9 = []
testing_only_libclang_5 = []
-testing_only_libclang_4 = []
-testing_only_libclang_3_9 = []
diff --git a/METADATA b/METADATA
index 85b1cce..c038164 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/bindgen
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "bindgen"
description: "Automatically generates Rust FFI bindings to C and C++ libraries."
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/bindgen/bindgen-0.59.2.crate"
+ value: "https://static.crates.io/crates/bindgen/bindgen-0.64.0.crate"
}
- version: "0.59.2"
+ version: "0.64.0"
license_type: NOTICE
last_upgrade_date {
- year: 2022
- month: 3
- day: 1
+ year: 2023
+ month: 2
+ day: 16
}
}
diff --git a/OWNERS b/OWNERS
index 46fc303..45dc4dd 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1 @@
-include platform/prebuilts/rust:/OWNERS
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
deleted file mode 100644
index 7b2dbbc..0000000
--- a/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-[![crates.io](https://img.shields.io/crates/v/bindgen.svg)](https://crates.io/crates/bindgen)
-[![docs.rs](https://docs.rs/bindgen/badge.svg)](https://docs.rs/bindgen/)
-
-# `bindgen`
-
-**`bindgen` automatically generates Rust FFI bindings to C (and some C++) libraries.**
-
-For example, given the C header `doggo.h`:
-
-```c
-typedef struct Doggo {
- int many;
- char wow;
-} Doggo;
-
-void eleven_out_of_ten_majestic_af(Doggo* pupper);
-```
-
-`bindgen` produces Rust FFI code allowing you to call into the `doggo` library's
-functions and use its types:
-
-```rust
-/* automatically generated by rust-bindgen 0.99.9 */
-
-#[repr(C)]
-pub struct Doggo {
- pub many: ::std::os::raw::c_int,
- pub wow: ::std::os::raw::c_char,
-}
-
-extern "C" {
- pub fn eleven_out_of_ten_majestic_af(pupper: *mut Doggo);
-}
-```
-
-## Users Guide
-
-[📚 Read the `bindgen` users guide here! 📚](https://rust-lang.github.io/rust-bindgen)
-
-## MSRV
-
-The minimum supported Rust version is **1.46**.
-
-No MSRV bump policy has been established yet, so MSRV may increase in any release.
-
-## API Reference
-
-[API reference documentation is on docs.rs](https://docs.rs/bindgen)
-
-## Environment Variables
-
-In addition to the [library API](https://docs.rs/bindgen) and [executable command-line API][bindgen-cmdline],
-`bindgen` can be controlled through environment variables.
-
-End-users should set these environment variables to modify `bindgen`'s behavior without modifying the source code of direct consumers of `bindgen`.
-
-- `BINDGEN_EXTRA_CLANG_ARGS`: extra arguments to pass to `clang`
- - Arguments are whitespace-separated
- - Use shell-style quoting to pass through whitespace
- - Examples:
- - Specify alternate sysroot: `--sysroot=/path/to/sysroot`
- - Add include search path with spaces: `-I"/path/with spaces"`
-- `BINDGEN_EXTRA_CLANG_ARGS_<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/TEST_MAPPING b/TEST_MAPPING
index e4ec3b3..23bbdf9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -3,22 +3,12 @@
"imports": [
{
"path": "external/rust/crates/libsqlite3-sys"
- }
- ],
- "presubmit": [
- {
- "name": "keystore2_test"
},
{
- "name": "legacykeystore_test"
- }
- ],
- "presubmit-rust": [
- {
- "name": "keystore2_test"
+ "path": "system/security/keystore2"
},
{
- "name": "legacykeystore_test"
+ "path": "system/security/keystore2/legacykeystore"
}
]
}
diff --git a/android/bindgen_cmd/Android.bp b/android/bindgen_cmd/Android.bp
index 758007b..689e7ae 100644
--- a/android/bindgen_cmd/Android.bp
+++ b/android/bindgen_cmd/Android.bp
@@ -20,6 +20,7 @@ rust_library_host {
],
rustlibs: [
"libbindgen",
+ "libbindgen_cli",
"libclap",
"libenv_logger",
],
diff --git a/android/bindgen_cmd/src/lib.rs b/android/bindgen_cmd/src/lib.rs
index a92ac80..d33da7f 100644
--- a/android/bindgen_cmd/src/lib.rs
+++ b/android/bindgen_cmd/src/lib.rs
@@ -23,11 +23,9 @@
//! on the the builder before it is used.
use bindgen;
+use bindgen_cli;
use std::env;
-#[path = "../../../src/options.rs"]
-mod options;
-
/// Takes in a function describing adjustments to make to a builder
/// initialized by the command line. `build(|x| x)` is equivalent to
/// running bindgen. When converting a build.rs, you will want to convert the
@@ -36,7 +34,7 @@ mod options;
pub fn build<C: FnOnce(bindgen::Builder) -> bindgen::Builder>(configure: C) {
env_logger::init();
- match options::builder_from_flags(env::args()) {
+ match bindgen_cli::builder_from_flags(env::args()) {
Ok((builder, output, _)) => {
configure(builder)
.generate()
diff --git a/build.rs b/build.rs
index fcc0bb2..8407cea 100644
--- a/build.rs
+++ b/build.rs
@@ -1,76 +1,15 @@
-mod target {
- use std::env;
- use std::fs::File;
- use std::io::Write;
- use std::path::{Path, PathBuf};
-
- pub fn main() {
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
-
- let mut dst =
- File::create(Path::new(&out_dir).join("host-target.txt")).unwrap();
- dst.write_all(env::var("TARGET").unwrap().as_bytes())
- .unwrap();
- }
-}
-
-mod testgen {
- use std::char;
- use std::env;
- use std::ffi::OsStr;
- use std::fs::{self, File};
- use std::io::Write;
- use std::path::{Path, PathBuf};
-
- pub fn main() {
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
- let mut dst =
- File::create(Path::new(&out_dir).join("tests.rs")).unwrap();
-
- let manifest_dir =
- PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
- let headers_dir = manifest_dir.join("tests").join("headers");
-
- let headers = match fs::read_dir(headers_dir) {
- Ok(dir) => dir,
- // We may not have headers directory after packaging.
- Err(..) => return,
- };
-
- let entries =
- headers.map(|result| result.expect("Couldn't read header file"));
-
- println!("cargo:rerun-if-changed=tests/headers");
-
- for entry in entries {
- match entry.path().extension().and_then(OsStr::to_str) {
- Some("h") | Some("hpp") => {
- let func = entry
- .file_name()
- .to_str()
- .unwrap()
- .replace(|c| !char::is_alphanumeric(c), "_")
- .replace("__", "_")
- .to_lowercase();
- writeln!(
- dst,
- "test_header!(header_{}, {:?});",
- func,
- entry.path(),
- )
- .unwrap();
- }
- _ => {}
- }
- }
-
- dst.flush().unwrap();
- }
-}
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::{Path, PathBuf};
fn main() {
- target::main();
- testgen::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
@@ -85,6 +24,6 @@ fn main() {
);
println!(
"cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}",
- std::env::var("TARGET").unwrap().replace("-", "_")
+ std::env::var("TARGET").unwrap().replace('-', "_")
);
}
diff --git a/src/callbacks.rs b/callbacks.rs
index 9b34544..dc20e25 100644
--- a/src/callbacks.rs
+++ b/callbacks.rs
@@ -5,7 +5,6 @@ pub use crate::ir::derive::CanDerive as ImplementsTrait;
pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue};
pub use crate::ir::int::IntKind;
use std::fmt;
-use std::panic::UnwindSafe;
/// An enum to allow ignoring parsing of macros.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -25,12 +24,27 @@ impl Default for MacroParsingBehavior {
/// A trait to allow configuring different kinds of types in different
/// situations.
-pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
+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
+ }
+
/// 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> {
@@ -100,7 +114,52 @@ pub trait ParseCallbacks: fmt::Debug + UnwindSafe {
///
/// If no additional attributes are wanted, this function should return an
/// empty `Vec`.
- fn add_derives(&self, _name: &str) -> Vec<String> {
+ fn add_derives(&self, _info: &DeriveInfo<'_>) -> Vec<String> {
vec![]
}
+
+ /// Process a source code comment.
+ fn process_comment(&self, _comment: &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,
+}
+
+/// An 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,
}
diff --git a/cargo2android.json b/cargo2android.json
index 9e5e68b..fd62b50 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -1,6 +1,6 @@
{
"copy-out": true,
- "features": "clap,runtime,which-rustfmt",
+ "features": "cli,experimental,runtime,which-rustfmt",
"host-first-multilib": true,
"run": true
-} \ No newline at end of file
+}
diff --git a/src/clang.rs b/clang.rs
index 074d459..32a2544 100644
--- a/src/clang.rs
+++ b/clang.rs
@@ -12,6 +12,40 @@ use std::hash::Hasher;
use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong};
use std::{mem, ptr, slice};
+/// Type representing a clang attribute.
+///
+/// Values of this type can be used to check for different attributes using the `has_attrs`
+/// function.
+pub struct Attribute {
+ name: &'static [u8],
+ kind: Option<CXCursorKind>,
+ token_kind: CXTokenKind,
+}
+
+impl Attribute {
+ /// A `warn_unused_result` attribute.
+ pub const MUST_USE: Self = Self {
+ name: b"warn_unused_result",
+ // FIXME(emilio): clang-sys doesn't expose `CXCursor_WarnUnusedResultAttr` (from clang 9).
+ kind: Some(440),
+ token_kind: CXToken_Identifier,
+ };
+
+ /// A `_Noreturn` attribute.
+ pub const NO_RETURN: Self = Self {
+ name: b"_Noreturn",
+ kind: None,
+ token_kind: CXToken_Keyword,
+ };
+
+ /// A `[[noreturn]]` attribute.
+ pub const NO_RETURN_CPP: Self = Self {
+ name: b"noreturn",
+ kind: None,
+ token_kind: CXToken_Identifier,
+ };
+}
+
/// A cursor into the Clang AST, pointing to an AST node.
///
/// We call the AST node pointed to by the cursor the cursor's "referent".
@@ -52,6 +86,11 @@ impl Cursor {
unsafe { clang_isDeclaration(self.kind()) != 0 }
}
+ /// Is this cursor's referent an anonymous record or so?
+ pub fn is_anonymous(&self) -> bool {
+ unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
+ }
+
/// Get this cursor's referent's spelling.
pub fn spelling(&self) -> String {
unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
@@ -276,6 +315,56 @@ impl Cursor {
true
}
+ /// Is the referent any kind of template parameter?
+ pub fn is_template_parameter(&self) -> bool {
+ matches!(
+ self.kind(),
+ CXCursor_TemplateTemplateParameter |
+ CXCursor_TemplateTypeParameter |
+ CXCursor_NonTypeTemplateParameter
+ )
+ }
+
+ /// Does the referent's type or value depend on a template parameter?
+ pub fn is_dependent_on_template_parameter(&self) -> bool {
+ fn visitor(
+ found_template_parameter: &mut bool,
+ cur: Cursor,
+ ) -> CXChildVisitResult {
+ // If we found a template parameter, it is dependent.
+ if cur.is_template_parameter() {
+ *found_template_parameter = true;
+ return CXChildVisit_Break;
+ }
+
+ // Get the referent and traverse it as well.
+ if let Some(referenced) = cur.referenced() {
+ if referenced.is_template_parameter() {
+ *found_template_parameter = true;
+ return CXChildVisit_Break;
+ }
+
+ referenced
+ .visit(|next| visitor(found_template_parameter, next));
+ if *found_template_parameter {
+ return CXChildVisit_Break;
+ }
+ }
+
+ // Continue traversing the AST at the original cursor.
+ CXChildVisit_Recurse
+ }
+
+ if self.is_template_parameter() {
+ return true;
+ }
+
+ let mut found_template_parameter = false;
+ self.visit(|next| visitor(&mut found_template_parameter, next));
+
+ found_template_parameter
+ }
+
/// Is this cursor pointing a valid referent?
pub fn is_valid(&self) -> bool {
unsafe { clang_isInvalid(self.kind()) == 0 }
@@ -485,9 +574,45 @@ impl Cursor {
!self.is_defaulted_function()
}
+ /// Is the referent a bit field declaration?
+ pub fn is_bit_field(&self) -> bool {
+ unsafe { clang_Cursor_isBitField(self.x) != 0 }
+ }
+
+ /// Get a cursor to the bit field's width expression, or `None` if it's not
+ /// a bit field.
+ pub fn bit_width_expr(&self) -> Option<Cursor> {
+ if !self.is_bit_field() {
+ return None;
+ }
+
+ let mut result = None;
+ self.visit(|cur| {
+ // The first child may or may not be a TypeRef, depending on whether
+ // the field's type is builtin. Skip it.
+ if cur.kind() == CXCursor_TypeRef {
+ return CXChildVisit_Continue;
+ }
+
+ // The next expression or literal is the bit width.
+ result = Some(cur);
+
+ CXChildVisit_Break
+ });
+
+ result
+ }
+
/// Get the width of this cursor's referent bit field, or `None` if the
- /// referent is not a bit field.
+ /// referent is not a bit field or if the width could not be evaluated.
pub fn bit_width(&self) -> Option<u32> {
+ // It is not safe to check the bit width without ensuring it doesn't
+ // depend on a template parameter. See
+ // https://github.com/rust-lang/rust-bindgen/issues/2239
+ if self.bit_width_expr()?.is_dependent_on_template_parameter() {
+ return None;
+ }
+
unsafe {
let w = clang_getFieldDeclBitWidth(self.x);
if w == -1 {
@@ -532,6 +657,7 @@ impl Cursor {
pub 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
@@ -545,6 +671,7 @@ impl Cursor {
pub 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
@@ -552,35 +679,41 @@ impl Cursor {
}
}
- /// Whether this cursor has the `warn_unused_result` attribute.
- pub fn has_warn_unused_result_attr(&self) -> bool {
- // FIXME(emilio): clang-sys doesn't expose this (from clang 9).
- const CXCursor_WarnUnusedResultAttr: CXCursorKind = 440;
- self.has_attr("warn_unused_result", Some(CXCursor_WarnUnusedResultAttr))
- }
+ /// Does this cursor have the given attributes?
+ pub fn has_attrs<const N: usize>(
+ &self,
+ attrs: &[Attribute; N],
+ ) -> [bool; N] {
+ let mut found_attrs = [false; N];
+ let mut found_count = 0;
- /// Does this cursor have the given attribute?
- ///
- /// `name` is checked against unexposed attributes.
- fn has_attr(&self, name: &str, clang_kind: Option<CXCursorKind>) -> bool {
- let mut found_attr = false;
self.visit(|cur| {
let kind = cur.kind();
- found_attr = clang_kind.map_or(false, |k| k == kind) ||
- (kind == CXCursor_UnexposedAttr &&
- cur.tokens().iter().any(|t| {
- t.kind == CXToken_Identifier &&
- t.spelling() == name.as_bytes()
- }));
-
- if found_attr {
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
+ 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_attr
+ found_attrs
}
/// Given that this cursor's referent is a `typedef`, get the `Type` that is
@@ -1697,7 +1830,7 @@ pub struct UnsavedFile {
impl UnsavedFile {
/// Construct a new unsaved file with the given `name` and `contents`.
- pub fn new(name: &str, contents: &str) -> UnsavedFile {
+ pub fn new(name: String, contents: String) -> UnsavedFile {
let name = CString::new(name).unwrap();
let contents = CString::new(contents).unwrap();
let x = CXUnsavedFile {
@@ -1789,9 +1922,15 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
format!(" {}number-of-template-args = {}", prefix, num),
);
}
- if let Some(width) = c.bit_width() {
+
+ 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,
@@ -2002,7 +2141,7 @@ impl EvalResult {
pub fn as_double(&self) -> Option<f64> {
match self.kind() {
CXEval_Float => {
- Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
+ Some(unsafe { clang_EvalResult_getAsDouble(self.x) })
}
_ => None,
}
@@ -2014,12 +2153,6 @@ impl EvalResult {
return None;
}
- if !clang_EvalResult_isUnsignedInt::is_loaded() {
- // FIXME(emilio): There's no way to detect underflow here, and clang
- // will just happily give us a value.
- return Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i64);
- }
-
if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 {
let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) };
if value > i64::max_value() as c_ulonglong {
@@ -2036,6 +2169,7 @@ impl EvalResult {
if value < i64::min_value() as c_longlong {
return None;
}
+ #[allow(clippy::unnecessary_cast)]
Some(value as i64)
}
@@ -2071,10 +2205,7 @@ pub struct TargetInfo {
impl TargetInfo {
/// Tries to obtain target information from libclang.
- pub fn new(tu: &TranslationUnit) -> Option<Self> {
- if !clang_getTranslationUnitTargetInfo::is_loaded() {
- return None;
- }
+ pub fn new(tu: &TranslationUnit) -> Self {
let triple;
let pointer_width;
unsafe {
@@ -2085,9 +2216,9 @@ impl TargetInfo {
}
assert!(pointer_width > 0);
assert_eq!(pointer_width % 8, 0);
- Some(TargetInfo {
+ TargetInfo {
triple,
pointer_width: pointer_width as usize,
- })
+ }
}
}
diff --git a/src/codegen/bitfield_unit.rs b/codegen/bitfield_unit.rs
index 73ec2bd..73ec2bd 100755..100644
--- a/src/codegen/bitfield_unit.rs
+++ b/codegen/bitfield_unit.rs
diff --git a/src/codegen/bitfield_unit_tests.rs b/codegen/bitfield_unit_tests.rs
index e143e4e..e143e4e 100644
--- a/src/codegen/bitfield_unit_tests.rs
+++ b/codegen/bitfield_unit_tests.rs
diff --git a/src/codegen/dyngen.rs b/codegen/dyngen.rs
index 71c4dab..d8ea811 100644
--- a/src/codegen/dyngen.rs
+++ b/codegen/dyngen.rs
@@ -1,5 +1,6 @@
use crate::codegen;
-use crate::ir::function::Abi;
+use crate::ir::context::BindgenContext;
+use crate::ir::function::ClangAbi;
use proc_macro2::Ident;
/// Used to build the output tokens for dynamic bindings.
@@ -72,12 +73,22 @@ impl DynamicItems {
Self::default()
}
- pub fn get_tokens(&self, lib_ident: Ident) -> proc_macro2::TokenStream {
+ pub 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;
@@ -92,7 +103,7 @@ impl DynamicItems {
) -> Result<Self, ::libloading::Error>
where P: AsRef<::std::ffi::OsStr> {
let library = ::libloading::Library::new(path)?;
- Self::from_library(library)
+ #from_library
}
pub unsafe fn from_library<L>(
@@ -112,16 +123,19 @@ impl DynamicItems {
}
}
- pub fn push(
+ #[allow(clippy::too_many_arguments)]
+ pub(crate) fn push(
&mut self,
ident: Ident,
- abi: Abi,
+ 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());
@@ -145,15 +159,18 @@ impl DynamicItems {
} else {
quote! { self.#ident.as_ref().expect("Expected function, got error.") }
};
- let call_body = quote! {
- (#fn_)(#( #args_identifiers ),*)
+ 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! {
- pub unsafe fn #ident ( &self, #( #args ),* ) -> #ret_ty {
+ #(#attributes)*
+ pub unsafe fn #ident ( &self, #( #args ),* ) #ret_ty {
#call_body
}
});
@@ -161,13 +178,19 @@ impl DynamicItems {
// 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(#ident_str).map(|sym| *sym)?;
+ let #ident = #library_get.map(|sym| *sym)?;
}
} else {
quote! {
- let #ident = __library.get(#ident_str).map(|sym| *sym);
+ let #ident = #library_get.map(|sym| *sym);
}
});
diff --git a/src/codegen/error.rs b/codegen/error.rs
index c1bcf4e..c1bcf4e 100644
--- a/src/codegen/error.rs
+++ b/codegen/error.rs
diff --git a/src/codegen/helpers.rs b/codegen/helpers.rs
index 2ce6894..088c7f9 100644
--- a/src/codegen/helpers.rs
+++ b/codegen/helpers.rs
@@ -30,7 +30,7 @@ pub mod attributes {
let which_ones = which_ones
.iter()
.cloned()
- .map(|one| Ident::new(one, Span::call_site()));
+ .map(|one| TokenStream::from_str(one).expect("derive to be valid"));
quote! {
#[derive( #( #which_ones ),* )]
}
@@ -55,9 +55,11 @@ pub mod attributes {
}
pub fn doc(comment: String) -> TokenStream {
- // NOTE(emilio): By this point comments are already preprocessed and in
- // `///` form. Quote turns them into `#[doc]` comments, but oh well.
- TokenStream::from_str(&comment).unwrap()
+ if comment.is_empty() {
+ quote!()
+ } else {
+ quote!(#[doc = #comment])
+ }
}
pub fn link_name(name: &str) -> TokenStream {
@@ -166,9 +168,19 @@ pub mod ast_ty {
#prefix::#ident
}
}
- None => quote! {
- ::std::os::raw::#ident
- },
+ None => {
+ if ctx.options().use_core &&
+ ctx.options().rust_features().core_ffi_c
+ {
+ quote! {
+ ::core::ffi::#ident
+ }
+ } else {
+ quote! {
+ ::std::os::raw::#ident
+ }
+ }
+ }
}
}
diff --git a/src/codegen/impl_debug.rs b/codegen/impl_debug.rs
index 0e2cd33..0e2cd33 100644
--- a/src/codegen/impl_debug.rs
+++ b/codegen/impl_debug.rs
diff --git a/src/codegen/impl_partialeq.rs b/codegen/impl_partialeq.rs
index 960306f..960306f 100644
--- a/src/codegen/impl_partialeq.rs
+++ b/codegen/impl_partialeq.rs
diff --git a/src/codegen/mod.rs b/codegen/mod.rs
index 19886e3..b6fb70e 100644
--- a/src/codegen/mod.rs
+++ b/codegen/mod.rs
@@ -3,6 +3,8 @@ mod error;
mod helpers;
mod impl_debug;
mod impl_partialeq;
+mod postprocessing;
+mod serialize;
pub mod struct_layout;
#[cfg(test)]
@@ -17,12 +19,12 @@ use self::struct_layout::StructLayoutTracker;
use super::BindgenOptions;
+use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind};
use crate::ir::analysis::{HasVtable, Sizedness};
use crate::ir::annotations::FieldAccessorKind;
-use crate::ir::comment;
use crate::ir::comp::{
- Base, Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData,
- FieldMethods, Method, MethodKind,
+ Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
+ Method, MethodKind,
};
use crate::ir::context::{BindgenContext, ItemId};
use crate::ir::derive::{
@@ -31,7 +33,9 @@ use crate::ir::derive::{
};
use crate::ir::dot;
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
-use crate::ir::function::{Abi, Function, FunctionKind, FunctionSig, Linkage};
+use crate::ir::function::{
+ Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
+};
use crate::ir::int::IntKind;
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
use crate::ir::item_kind::ItemKind;
@@ -56,6 +60,29 @@ use std::iter;
use std::ops;
use std::str::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 std::fmt::Display for CodegenError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CodegenError::Serialize { msg, loc } => {
+ write!(f, "serialization error at {}: {}", loc, msg)
+ }
+ CodegenError::Io(err) => err.fmt(f),
+ }
+ }
+}
+
// Name of type defined in constified enum module
pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type";
@@ -84,7 +111,7 @@ fn root_import(
let mut path = top_level_path(ctx, module);
let root = ctx.root_module().canonical_name(ctx);
- let root_ident = ctx.rust_ident(&root);
+ let root_ident = ctx.rust_ident(root);
path.push(quote! { #root_ident });
let mut tokens = quote! {};
@@ -110,17 +137,13 @@ bitflags! {
}
}
-fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
+fn derives_of_item(
+ item: &Item,
+ ctx: &BindgenContext,
+ packed: bool,
+) -> DerivableTraits {
let mut derivable_traits = DerivableTraits::empty();
- if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
- derivable_traits |= DerivableTraits::DEBUG;
- }
-
- if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
- derivable_traits |= DerivableTraits::DEFAULT;
- }
-
let all_template_params = item.all_template_params(ctx);
if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
@@ -137,6 +160,18 @@ fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
// 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) {
@@ -230,6 +265,8 @@ struct CodegenResult<'a> {
/// 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>,
+
+ items_to_serialize: Vec<ItemId>,
}
impl<'a> CodegenResult<'a> {
@@ -247,6 +284,7 @@ impl<'a> CodegenResult<'a> {
functions_seen: Default::default(),
vars_seen: Default::default(),
overload_counters: Default::default(),
+ items_to_serialize: Default::default(),
}
}
@@ -424,10 +462,10 @@ trait CodeGenerator {
/// Extra information returned to the caller.
type Return;
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
extra: &Self::Extra,
) -> Self::Return;
}
@@ -467,10 +505,10 @@ impl CodeGenerator for Item {
type Extra = ();
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
_extra: &(),
) {
debug!("<Item as CodeGenerator>::codegen: self = {:?}", self);
@@ -499,10 +537,10 @@ impl CodeGenerator for Module {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
debug!("<Module as CodeGenerator>::codegen: item = {:?}", item);
@@ -591,10 +629,10 @@ impl CodeGenerator for Var {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
use crate::ir::var::VarType;
@@ -738,10 +776,10 @@ impl CodeGenerator for Type {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
debug!("<Type as CodeGenerator>::codegen: item = {:?}", item);
@@ -788,7 +826,7 @@ impl CodeGenerator for Type {
}
};
- let rust_name = ctx.rust_ident(&name);
+ let rust_name = ctx.rust_ident(name);
let mut tokens = if let Some(comment) = item.comment(ctx) {
attributes::doc(comment)
@@ -828,9 +866,34 @@ impl CodeGenerator for Type {
}
// If this is a known named type, disallow generating anything
- // for it too.
+ // 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;
}
@@ -926,7 +989,9 @@ impl CodeGenerator for Type {
let mut attributes =
vec![attributes::repr("transparent")];
- let derivable_traits = derives_of_item(item, ctx);
+ 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))
@@ -1017,23 +1082,14 @@ impl CodeGenerator for Type {
struct Vtable<'a> {
item_id: ItemId,
+ /// A reference to the originating compound object.
#[allow(dead_code)]
- methods: &'a [Method],
- #[allow(dead_code)]
- base_classes: &'a [Base],
+ comp_info: &'a CompInfo,
}
impl<'a> Vtable<'a> {
- fn new(
- item_id: ItemId,
- methods: &'a [Method],
- base_classes: &'a [Base],
- ) -> Self {
- Vtable {
- item_id,
- methods,
- base_classes,
- }
+ fn new(item_id: ItemId, comp_info: &'a CompInfo) -> Self {
+ Vtable { item_id, comp_info }
}
}
@@ -1041,23 +1097,77 @@ impl<'a> CodeGenerator for Vtable<'a> {
type Extra = Item;
type Return = ();
- fn codegen<'b>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'b>,
+ 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, generate an empty struct, later we should generate function
- // pointers and whatnot.
- let name = ctx.rust_ident(&self.canonical_name(ctx));
- let void = helpers::ast_ty::c_void(ctx);
- result.push(quote! {
- #[repr(C)]
- pub struct #name ( #void );
- });
+ // 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 );
+ });
+ }
}
}
@@ -1086,10 +1196,10 @@ impl CodeGenerator for TemplateInstantiation {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
debug_assert!(item.is_enabled_for_codegen(ctx));
@@ -1157,11 +1267,11 @@ impl CodeGenerator for TemplateInstantiation {
trait FieldCodegen<'a> {
type Extra;
+ #[allow(clippy::too_many_arguments)]
fn codegen<F, M>(
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1181,7 +1291,6 @@ impl<'a> FieldCodegen<'a> for Field {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1198,7 +1307,6 @@ impl<'a> FieldCodegen<'a> for Field {
data.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1212,7 +1320,6 @@ impl<'a> FieldCodegen<'a> for Field {
unit.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1226,6 +1333,35 @@ impl<'a> FieldCodegen<'a> for Field {
}
}
+fn wrap_union_field_if_needed(
+ ctx: &BindgenContext,
+ struct_layout: &StructLayoutTracker,
+ ty: proc_macro2::TokenStream,
+ result: &mut CodegenResult,
+) -> proc_macro2::TokenStream {
+ if struct_layout.is_rust_union() {
+ if struct_layout.can_copy_union_fields() {
+ ty
+ } else {
+ let prefix = ctx.trait_prefix();
+ quote! {
+ ::#prefix::mem::ManuallyDrop<#ty>
+ }
+ }
+ } else {
+ result.saw_bindgen_union();
+ if ctx.options().enable_cxx_namespaces {
+ quote! {
+ root::__BindgenUnionField<#ty>
+ }
+ } else {
+ quote! {
+ __BindgenUnionField<#ty>
+ }
+ }
+ }
+}
+
impl<'a> FieldCodegen<'a> for FieldData {
type Extra = ();
@@ -1233,7 +1369,6 @@ impl<'a> FieldCodegen<'a> for FieldData {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1256,17 +1391,8 @@ impl<'a> FieldCodegen<'a> for FieldData {
ty.append_implicit_template_params(ctx, field_item);
// NB: If supported, we use proper `union` types.
- let ty = if parent.is_union() && !struct_layout.is_rust_union() {
- result.saw_bindgen_union();
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#ty>
- }
- } else {
- quote! {
- __BindgenUnionField<#ty>
- }
- }
+ 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();
@@ -1288,8 +1414,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
let mut field = quote! {};
if ctx.options().generate_comments {
if let Some(raw_comment) = self.comment() {
- let comment =
- comment::preprocess(raw_comment, codegen_depth + 1);
+ let comment = ctx.options().process_comment(raw_comment);
field = attributes::doc(comment);
}
}
@@ -1449,7 +1574,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1467,26 +1591,20 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
let layout = self.layout();
let unit_field_ty = helpers::bitfield_unit(ctx, layout);
- let field_ty = {
- if parent.is_union() && !struct_layout.is_rust_union() {
- result.saw_bindgen_union();
- if ctx.options().enable_cxx_namespaces {
- quote! {
- root::__BindgenUnionField<#unit_field_ty>
- }
- } else {
- quote! {
- __BindgenUnionField<#unit_field_ty>
- }
- }
- } else {
- unit_field_ty.clone()
- }
+ let field_ty = if parent.is_union() {
+ wrap_union_field_if_needed(
+ ctx,
+ struct_layout,
+ unit_field_ty.clone(),
+ result,
+ )
+ } else {
+ unit_field_ty.clone()
};
{
let align_field_name = format!("_bitfield_align_{}", self.nth());
- let align_field_ident = ctx.rust_ident(&align_field_name);
+ let align_field_ident = ctx.rust_ident(align_field_name);
let align_ty = match self.layout().align {
n if n >= 8 => quote! { u64 },
4 => quote! { u32 },
@@ -1532,7 +1650,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
bf.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1607,7 +1724,6 @@ impl<'a> FieldCodegen<'a> for Bitfield {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- _codegen_depth: usize,
_accessor_kind: FieldAccessorKind,
parent: &CompInfo,
_result: &mut CodegenResult,
@@ -1708,10 +1824,10 @@ impl CodeGenerator for CompInfo {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item);
@@ -1749,8 +1865,7 @@ impl CodeGenerator for CompInfo {
if !is_opaque {
if item.has_vtable_ptr(ctx) {
- let vtable =
- Vtable::new(item.id(), self.methods(), self.base_members());
+ let vtable = Vtable::new(item.id(), self);
vtable.codegen(ctx, result, item);
let vtable_type = vtable
@@ -1786,7 +1901,6 @@ impl CodeGenerator for CompInfo {
let mut methods = vec![];
if !is_opaque {
- let codegen_depth = item.codegen_depth(ctx);
let fields_should_be_private =
item.annotations().private_fields().unwrap_or(false);
let struct_accessor_kind = item
@@ -1797,7 +1911,6 @@ impl CodeGenerator for CompInfo {
field.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
struct_accessor_kind,
self,
result,
@@ -1982,7 +2095,7 @@ impl CodeGenerator for CompInfo {
}
}
- let derivable_traits = derives_of_item(item, ctx);
+ 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 &&
@@ -2015,25 +2128,32 @@ impl CodeGenerator for CompInfo {
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;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&canonical_name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
+ 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.annotations().must_use_type() || ctx.must_use_type_by_name(item)
- {
+ if item.must_use(ctx) {
attributes.push(attributes::must_use());
}
- let mut tokens = if is_union && struct_layout.is_rust_union() {
+ let mut tokens = if is_rust_union {
quote! {
#( #attributes )*
pub union #canonical_ident
@@ -2108,56 +2228,58 @@ impl CodeGenerator for CompInfo {
})
};
- // FIXME when [issue #465](https://github.com/rust-lang/rust-bindgen/issues/465) ready
- let too_many_base_vtables = self
- .base_members()
- .iter()
- .filter(|base| base.ty.has_vtable(ctx))
- .count() >
- 1;
-
- let should_skip_field_offset_checks =
- is_opaque || too_many_base_vtables;
+ let should_skip_field_offset_checks = is_opaque;
let check_field_offset = if should_skip_field_offset_checks
{
vec![]
} else {
- let asserts = self.fields()
- .iter()
- .filter_map(|field| match *field {
- Field::DataMember(ref f) if f.name().is_some() => Some(f),
- _ => None,
- })
- .flat_map(|field| {
- let name = field.name().unwrap();
- field.offset().map(|offset| {
- let field_offset = offset / 8;
- let field_name = ctx.rust_ident(name);
-
- quote! {
- assert_eq!(
- unsafe {
- &(*(::#prefix::ptr::null::<#canonical_ident>())).#field_name as *const _ as usize
- },
- #field_offset,
- concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
- );
- }
- })
+ 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::<Vec<proc_macro2::TokenStream>>();
+ })
+ .collect()
+ };
- asserts
+ 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 )*
}
@@ -2310,24 +2432,13 @@ impl CodeGenerator for CompInfo {
}
}
-trait MethodCodegen {
- fn codegen_method<'a>(
+impl Method {
+ fn codegen_method(
&self,
ctx: &BindgenContext,
methods: &mut Vec<proc_macro2::TokenStream>,
- method_names: &mut HashMap<String, usize>,
- result: &mut CodegenResult<'a>,
- parent: &CompInfo,
- );
-}
-
-impl MethodCodegen for Method {
- fn codegen_method<'a>(
- &self,
- ctx: &BindgenContext,
- methods: &mut Vec<proc_macro2::TokenStream>,
- method_names: &mut HashMap<String, usize>,
- result: &mut CodegenResult<'a>,
+ method_names: &mut HashSet<String>,
+ result: &mut CodegenResult<'_>,
_parent: &CompInfo,
) {
assert!({
@@ -2370,9 +2481,20 @@ impl MethodCodegen for Method {
_ => panic!("How in the world?"),
};
- if let (Abi::ThisCall, false) =
- (signature.abi(), ctx.options().rust_features().thiscall_abi)
- {
+ let supported_abi = match signature.abi(ctx, Some(&*name)) {
+ ClangAbi::Known(Abi::ThisCall) => {
+ ctx.options().rust_features().thiscall_abi
+ }
+ ClangAbi::Known(Abi::Vectorcall) => {
+ ctx.options().rust_features().vectorcall_abi
+ }
+ ClangAbi::Known(Abi::CUnwind) => {
+ ctx.options().rust_features().c_unwind_abi
+ }
+ _ => true,
+ };
+
+ if !supported_abi {
return;
}
@@ -2382,16 +2504,22 @@ impl MethodCodegen for Method {
return;
}
- let count = {
- let count = method_names.entry(name.clone()).or_insert(0);
- *count += 1;
- *count - 1
- };
+ if method_names.contains(&name) {
+ let mut count = 1;
+ let mut new_name;
- if count != 0 {
- name.push_str(&count.to_string());
+ 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();
@@ -2472,9 +2600,7 @@ impl MethodCodegen for Method {
})
}
- let block = quote! {
- #( #stmts );*
- };
+ let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*));
let mut attrs = vec![attributes::inline()];
@@ -2495,7 +2621,7 @@ impl MethodCodegen for Method {
}
/// A helper type that represents different enum variations.
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[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
@@ -2508,6 +2634,8 @@ pub enum EnumVariation {
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,
@@ -2545,16 +2673,26 @@ impl std::str::FromStr for EnumVariation {
"rust_non_exhaustive" => Ok(EnumVariation::Rust {
non_exhaustive: true,
}),
- "bitfield" => Ok(EnumVariation::NewType { is_bitfield: 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 }),
+ "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', and 'newtype'."
+ "'moduleconsts', 'newtype' and 'newtype_global'."
),
)),
}
@@ -2564,41 +2702,27 @@ impl std::str::FromStr for EnumVariation {
/// A helper type to construct different enum variations.
enum EnumBuilder<'a> {
Rust {
- codegen_depth: usize,
attrs: Vec<proc_macro2::TokenStream>,
ident: Ident,
tokens: proc_macro2::TokenStream,
emitted_any_variants: bool,
},
NewType {
- codegen_depth: usize,
canonical_name: &'a str,
tokens: proc_macro2::TokenStream,
is_bitfield: bool,
+ is_global: bool,
},
Consts {
- repr: proc_macro2::TokenStream,
variants: Vec<proc_macro2::TokenStream>,
- codegen_depth: usize,
},
ModuleConsts {
- codegen_depth: usize,
module_name: &'a str,
module_items: Vec<proc_macro2::TokenStream>,
},
}
impl<'a> EnumBuilder<'a> {
- /// Returns the depth of the code generation for a variant of this enum.
- fn codegen_depth(&self) -> usize {
- match *self {
- EnumBuilder::Rust { codegen_depth, .. } |
- EnumBuilder::NewType { codegen_depth, .. } |
- EnumBuilder::ModuleConsts { codegen_depth, .. } |
- EnumBuilder::Consts { codegen_depth, .. } => codegen_depth,
- }
- }
-
/// Returns true if the builder is for a rustified enum.
fn is_rust_enum(&self) -> bool {
matches!(*self, EnumBuilder::Rust { .. })
@@ -2611,19 +2735,22 @@ impl<'a> EnumBuilder<'a> {
mut attrs: Vec<proc_macro2::TokenStream>,
repr: proc_macro2::TokenStream,
enum_variation: EnumVariation,
- enum_codegen_depth: usize,
+ has_typedef: bool,
) -> Self {
let ident = Ident::new(name, Span::call_site());
match enum_variation {
- EnumVariation::NewType { is_bitfield } => EnumBuilder::NewType {
- codegen_depth: enum_codegen_depth,
+ 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 { .. } => {
@@ -2631,7 +2758,6 @@ impl<'a> EnumBuilder<'a> {
attrs.insert(0, quote! { #[repr( #repr )] });
let tokens = quote!();
EnumBuilder::Rust {
- codegen_depth: enum_codegen_depth + 1,
attrs,
ident,
tokens,
@@ -2642,16 +2768,14 @@ impl<'a> EnumBuilder<'a> {
EnumVariation::Consts => {
let mut variants = Vec::new();
- variants.push(quote! {
- #( #attrs )*
- pub type #ident = #repr;
- });
-
- EnumBuilder::Consts {
- repr,
- variants,
- codegen_depth: enum_codegen_depth,
+ if !has_typedef {
+ variants.push(quote! {
+ #( #attrs )*
+ pub type #ident = #repr;
+ });
}
+
+ EnumBuilder::Consts { variants }
}
EnumVariation::ModuleConsts => {
@@ -2665,7 +2789,6 @@ impl<'a> EnumBuilder<'a> {
};
EnumBuilder::ModuleConsts {
- codegen_depth: enum_codegen_depth + 1,
module_name: name,
module_items: vec![type_definition],
}
@@ -2674,13 +2797,13 @@ impl<'a> EnumBuilder<'a> {
}
/// Add a variant to this enum.
- fn with_variant<'b>(
+ fn with_variant(
self,
ctx: &BindgenContext,
variant: &EnumVariant,
mangling_prefix: Option<&str>,
rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'b>,
+ result: &mut CodegenResult<'_>,
is_ty_named: bool,
) -> Self {
let variant_name = ctx.rust_mangle(variant.name());
@@ -2697,8 +2820,7 @@ impl<'a> EnumBuilder<'a> {
let mut doc = quote! {};
if ctx.options().generate_comments {
if let Some(raw_comment) = variant.comment() {
- let comment =
- comment::preprocess(raw_comment, self.codegen_depth());
+ let comment = ctx.options().process_comment(raw_comment);
doc = attributes::doc(comment);
}
}
@@ -2709,13 +2831,11 @@ impl<'a> EnumBuilder<'a> {
ident,
tokens,
emitted_any_variants: _,
- codegen_depth,
} => {
let name = ctx.rust_ident(variant_name);
EnumBuilder::Rust {
attrs,
ident,
- codegen_depth,
tokens: quote! {
#tokens
#doc
@@ -2725,11 +2845,18 @@ impl<'a> EnumBuilder<'a> {
}
}
- EnumBuilder::NewType { canonical_name, .. } => {
- if ctx.options().rust_features().associated_const && is_ty_named
+ 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
@@ -2752,7 +2879,7 @@ impl<'a> EnumBuilder<'a> {
self
}
- EnumBuilder::Consts { ref repr, .. } => {
+ EnumBuilder::Consts { .. } => {
let constant_name = match mangling_prefix {
Some(prefix) => {
Cow::Owned(format!("{}_{}", prefix, variant_name))
@@ -2760,18 +2887,15 @@ impl<'a> EnumBuilder<'a> {
None => variant_name,
};
- let ty = if is_ty_named { &rust_ty } else { repr };
-
let ident = ctx.rust_ident(constant_name);
result.push(quote! {
#doc
- pub const #ident : #ty = #expr ;
+ pub const #ident : #rust_ty = #expr ;
});
self
}
EnumBuilder::ModuleConsts {
- codegen_depth,
module_name,
mut module_items,
} => {
@@ -2785,17 +2909,16 @@ impl<'a> EnumBuilder<'a> {
EnumBuilder::ModuleConsts {
module_name,
module_items,
- codegen_depth,
}
}
}
}
- fn build<'b>(
+ fn build(
self,
ctx: &BindgenContext,
rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'b>,
+ result: &mut CodegenResult<'_>,
) -> proc_macro2::TokenStream {
match self {
EnumBuilder::Rust {
@@ -2894,10 +3017,10 @@ impl CodeGenerator for Enum {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) {
debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item);
@@ -2998,21 +3121,16 @@ impl CodeGenerator for Enum {
attrs.push(attributes::doc(comment));
}
- if item.annotations().must_use_type() || ctx.must_use_type_by_name(item)
- {
+ if item.must_use(ctx) {
attrs.push(attributes::must_use());
}
if !variation.is_const() {
- let mut derives = derives_of_item(item, ctx);
- // For backwards compat, enums always derive Debug/Clone/Eq/PartialEq/Hash, even
- // if we don't generate those by default.
- if !item.annotations().disallow_debug() {
- derives.insert(DerivableTraits::DEBUG);
- }
- if !item.annotations().disallow_copy() {
- derives.insert(DerivableTraits::COPY);
- }
+ 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 |
@@ -3028,17 +3146,19 @@ impl CodeGenerator for Enum {
// The custom derives callback may return a list of derive attributes;
// add them to the end of the list.
- let custom_derives;
- if let Some(cb) = &ctx.options().parse_callbacks {
- custom_derives = cb.add_derives(&name);
- // In most cases this will be a no-op, since custom_derives will be empty.
- derives.extend(custom_derives.iter().map(|s| s.as_str()));
- };
+ 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<'a>(
+ fn add_constant(
ctx: &BindgenContext,
enum_: &Type,
// Only to avoid recomputing every time.
@@ -3049,7 +3169,7 @@ impl CodeGenerator for Enum {
variant_name: &Ident,
referenced_name: &Ident,
enum_rust_ty: proc_macro2::TokenStream,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
) {
let constant_name = if enum_.name().is_some() {
if ctx.options().prepend_enum_name {
@@ -3069,14 +3189,10 @@ impl CodeGenerator for Enum {
}
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,
- item.codegen_depth(ctx),
- );
+ 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();
@@ -3154,7 +3270,7 @@ impl CodeGenerator for Enum {
ctx,
enum_ty,
&ident,
- &Ident::new(&*mangled_name, Span::call_site()),
+ &Ident::new(&mangled_name, Span::call_site()),
existing_variant_name,
enum_rust_ty.clone(),
result,
@@ -3223,7 +3339,7 @@ impl CodeGenerator for Enum {
}
/// Enum for the default type of macro constants.
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum MacroTypeVariation {
/// Use i32 or i64
Signed,
@@ -3267,7 +3383,7 @@ impl std::str::FromStr for MacroTypeVariation {
}
/// Enum for how aliases should be translated.
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum AliasVariation {
/// Convert to regular Rust alias
TypeAlias,
@@ -3314,6 +3430,52 @@ impl std::str::FromStr for AliasVariation {
}
}
+/// Enum for how non-Copy unions should be translated.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum NonCopyUnionStyle {
+ /// Wrap members in a type generated by bindgen.
+ BindgenWrapper,
+ /// Wrap members in [`::core::mem::ManuallyDrop`].
+ ///
+ /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
+ /// MSRV is lower.
+ ManuallyDrop,
+}
+
+impl NonCopyUnionStyle {
+ /// Convert an `NonCopyUnionStyle` to its str representation.
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ Self::BindgenWrapper => "bindgen_wrapper",
+ Self::ManuallyDrop => "manually_drop",
+ }
+ }
+}
+
+impl Default for NonCopyUnionStyle {
+ fn default() -> Self {
+ Self::BindgenWrapper
+ }
+}
+
+impl std::str::FromStr for NonCopyUnionStyle {
+ type Err = std::io::Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "bindgen_wrapper" => Ok(Self::BindgenWrapper),
+ "manually_drop" => Ok(Self::ManuallyDrop),
+ _ => Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ concat!(
+ "Got an invalid NonCopyUnionStyle. Accepted values ",
+ "are 'bindgen_wrapper' and 'manually_drop'"
+ ),
+ )),
+ }
+ }
+}
+
/// Fallible conversion to an opaque blob.
///
/// Implementors of this trait should provide the `try_get_layout` method to
@@ -3705,7 +3867,7 @@ impl TryToRustTy for Type {
}
TypeKind::TypeParam => {
let name = item.canonical_name(ctx);
- let ident = ctx.rust_ident(&name);
+ let ident = ctx.rust_ident(name);
Ok(quote! {
#ident
})
@@ -3821,13 +3983,27 @@ impl TryToRustTy for FunctionSig {
// TODO: we might want to consider ignoring the reference return value.
let ret = utils::fnsig_return_ty(ctx, self);
let arguments = utils::fnsig_arguments(ctx, self);
- let abi = self.abi();
+ let abi = self.abi(ctx, None);
match abi {
- Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
+ ClangAbi::Known(Abi::ThisCall)
+ if !ctx.options().rust_features().thiscall_abi =>
+ {
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
Ok(proc_macro2::TokenStream::new())
}
+ ClangAbi::Known(Abi::Vectorcall)
+ if !ctx.options().rust_features().vectorcall_abi =>
+ {
+ warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
+ Ok(proc_macro2::TokenStream::new())
+ }
+ ClangAbi::Known(Abi::CUnwind)
+ if !ctx.options().rust_features().c_unwind_abi =>
+ {
+ warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target");
+ Ok(proc_macro2::TokenStream::new())
+ }
_ => Ok(quote! {
unsafe extern #abi fn ( #( #arguments ),* ) #ret
}),
@@ -3842,32 +4018,40 @@ impl CodeGenerator for Function {
/// it.
type Return = Option<u32>;
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ result: &mut CodegenResult<'_>,
item: &Item,
) -> Self::Return {
debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));
- // We can't currently do anything with Internal functions so just
- // avoid generating anything for them.
- match self.linkage() {
- Linkage::Internal => return None,
- Linkage::External => {}
+ let is_internal = matches!(self.linkage(), Linkage::Internal);
+
+ if is_internal {
+ if ctx.options().wrap_static_fns {
+ result.items_to_serialize.push(item.id());
+ } else {
+ // We can't do anything with Internal functions if we are not wrapping them so just
+ // avoid generating anything for them.
+ return None;
+ }
}
// Pure virtual methods have no actual symbol, so we can't generate
// something meaningful for them.
- match self.kind() {
+ 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
@@ -3904,26 +4088,49 @@ impl CodeGenerator for Function {
let mut attributes = vec![];
- if signature.must_use() &&
- ctx.options().rust_features().must_use_function
- {
- attributes.push(attributes::must_use());
+ if ctx.options().rust_features().must_use_function {
+ let must_use = signature.must_use() || {
+ let ret_ty = signature
+ .return_type()
+ .into_resolver()
+ .through_type_refs()
+ .resolve(ctx);
+ ret_ty.must_use(ctx)
+ };
+
+ if must_use {
+ attributes.push(attributes::must_use());
+ }
}
if let Some(comment) = item.comment(ctx) {
attributes.push(attributes::doc(comment));
}
- let abi = match signature.abi() {
- Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => {
+ let abi = match signature.abi(ctx, Some(name)) {
+ ClangAbi::Known(Abi::ThisCall)
+ if !ctx.options().rust_features().thiscall_abi =>
+ {
warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target");
return None;
}
- Abi::Win64 if signature.is_variadic() => {
+ ClangAbi::Known(Abi::Vectorcall)
+ if !ctx.options().rust_features().vectorcall_abi =>
+ {
+ warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target");
+ return None;
+ }
+ ClangAbi::Known(Abi::CUnwind)
+ if !ctx.options().rust_features().c_unwind_abi =>
+ {
+ warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target");
+ return None;
+ }
+ ClangAbi::Known(Abi::Win64) if signature.is_variadic() => {
warn!("Skipping variadic function with Win64 ABI that isn't supported");
return None;
}
- Abi::Unknown(unknown_abi) => {
+ ClangAbi::Unknown(unknown_abi) => {
panic!(
"Invalid or unknown abi {:?} for function {:?} ({:?})",
unknown_abi, canonical_name, self
@@ -3939,13 +4146,17 @@ impl CodeGenerator for Function {
write!(&mut canonical_name, "{}", times_seen).unwrap();
}
+ let mut has_link_name_attr = false;
let link_name = mangled_name.unwrap_or(name);
- if !utils::names_will_be_identical_after_mangling(
- &canonical_name,
- link_name,
- Some(abi),
- ) {
+ if !is_dynamic_function &&
+ !utils::names_will_be_identical_after_mangling(
+ &canonical_name,
+ link_name,
+ Some(abi),
+ )
+ {
attributes.push(attributes::link_name(link_name));
+ has_link_name_attr = true;
}
// Unfortunately this can't piggyback on the `attributes` list because
@@ -3956,6 +4167,11 @@ impl CodeGenerator for Function {
quote! { #[link(wasm_import_module = #name)] }
});
+ if is_internal && ctx.options().wrap_static_fns && !has_link_name_attr {
+ let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
+ attributes.push(attributes::link_name(&name));
+ }
+
let ident = ctx.rust_ident(canonical_name);
let tokens = quote! {
#wasm_link_attribute
@@ -3966,16 +4182,10 @@ impl CodeGenerator for Function {
};
// If we're doing dynamic binding generation, add to the dynamic items.
- if ctx.options().dynamic_library_name.is_some() &&
- self.kind() == FunctionKind::Function
- {
+ if is_dynamic_function {
let args_identifiers =
utils::fnsig_argument_identifiers(ctx, signature);
- let return_item = ctx.resolve_item(signature.return_type());
- let ret_ty = match *return_item.kind().expect_type().kind() {
- TypeKind::Void => quote! {()},
- _ => return_item.to_rust_ty_or_opaque(ctx, &()),
- };
+ let ret_ty = utils::fnsig_return_ty(ctx, signature);
result.dynamic_items().push(
ident,
abi,
@@ -3985,6 +4195,8 @@ impl CodeGenerator for Function {
args_identifiers,
ret,
ret_ty,
+ attributes,
+ ctx,
);
} else {
result.push(tokens);
@@ -3996,9 +4208,19 @@ impl CodeGenerator for Function {
fn objc_method_codegen(
ctx: &BindgenContext,
method: &ObjCMethod,
+ methods: &mut Vec<proc_macro2::TokenStream>,
class_name: Option<&str>,
+ rust_class_name: &str,
prefix: &str,
-) -> proc_macro2::TokenStream {
+) {
+ // 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);
@@ -4018,48 +4240,54 @@ fn objc_method_codegen(
let methods_and_args = method.format_method_call(&fn_args);
- let body = if method.is_class_method() {
- let class_name = ctx.rust_ident(
- class_name
- .expect("Generating a class method without class name?")
- .to_owned(),
- );
- quote! {
- msg_send!(class!(#class_name), #methods_and_args)
- }
- } else {
- quote! {
- msg_send!(*self, #methods_and_args)
- }
+ let 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()));
- quote! {
+ methods.push(quote! {
unsafe fn #method_name #sig where <Self as std::ops::Deref>::Target: objc::Message + Sized {
#body
}
- }
+ });
}
impl CodeGenerator for ObjCInterface {
type Extra = Item;
type Return = ();
- fn codegen<'a>(
+ fn codegen(
&self,
ctx: &BindgenContext,
- result: &mut CodegenResult<'a>,
+ 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() {
- let impl_item = objc_method_codegen(ctx, method, None, "");
- impl_items.push(impl_item);
+ objc_method_codegen(
+ ctx,
+ method,
+ &mut impl_items,
+ None,
+ &rust_class_name,
+ "",
+ );
}
for class_method in self.class_methods() {
@@ -4069,13 +4297,14 @@ impl CodeGenerator for ObjCInterface {
.map(|m| m.rust_name())
.any(|x| x == class_method.rust_name());
let prefix = if ambiquity { "class_" } else { "" };
- let impl_item = objc_method_codegen(
+ objc_method_codegen(
ctx,
class_method,
+ &mut impl_items,
Some(self.name()),
+ &rust_class_name,
prefix,
);
- impl_items.push(impl_item);
}
let trait_name = ctx.rust_ident(self.rust_name());
@@ -4090,7 +4319,7 @@ impl CodeGenerator for ObjCInterface {
.collect();
quote! {
- pub trait #trait_name <#(#template_names),*> : #trait_constraints {
+ pub trait #trait_name <#(#template_names:'static),*> : #trait_constraints {
#( #impl_items )*
}
}
@@ -4106,7 +4335,7 @@ impl CodeGenerator for ObjCInterface {
if !self.is_category() && !self.is_protocol() {
let struct_block = quote! {
#[repr(transparent)]
- #[derive(Clone)]
+ #[derive(Debug, Copy, Clone)]
pub struct #class_name(pub id);
impl std::ops::Deref for #class_name {
type Target = objc::runtime::Object;
@@ -4120,7 +4349,7 @@ impl CodeGenerator for ObjCInterface {
impl #class_name {
pub fn alloc() -> Self {
Self(unsafe {
- msg_send!(objc::class!(#class_name), alloc)
+ msg_send!(class!(#class_name), alloc)
})
}
}
@@ -4247,7 +4476,8 @@ impl CodeGenerator for ObjCInterface {
pub(crate) fn codegen(
context: BindgenContext,
-) -> (Vec<proc_macro2::TokenStream>, BindgenOptions) {
+) -> Result<(proc_macro2::TokenStream, BindgenOptions, Vec<String>), CodegenError>
+{
context.gen(|context| {
let _t = context.timer("codegen");
let counter = Cell::new(0);
@@ -4293,25 +4523,77 @@ pub(crate) fn codegen(
if let Some(ref lib_name) = context.options().dynamic_library_name {
let lib_ident = context.rust_ident(lib_name);
let dynamic_items_tokens =
- result.dynamic_items().get_tokens(lib_ident);
+ result.dynamic_items().get_tokens(lib_ident, context);
result.push(dynamic_items_tokens);
}
- result.items
+ utils::serialize_items(&result, context)?;
+
+ Ok(postprocessing::postprocessing(
+ result.items,
+ context.options(),
+ ))
})
}
pub mod utils {
- use super::{error, ToRustTyOrOpaque};
+ use super::serialize::CSerialize;
+ use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
use crate::ir::context::BindgenContext;
- use crate::ir::function::{Abi, FunctionSig};
+ 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 proc_macro2;
use std::borrow::Cow;
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();
+
+ for &id in &result.items_to_serialize {
+ let item = context.resolve_item(id);
+ item.serialize(context, (), &mut vec![], &mut code)?;
+ }
+
+ std::fs::write(source_path, code)?;
+
+ Ok(())
+ }
+
pub fn prepend_bitfield_unit_type(
ctx: &BindgenContext,
result: &mut Vec<proc_macro2::TokenStream>,
@@ -4342,7 +4624,7 @@ pub mod utils {
}
} else {
quote! {
- use objc;
+ use objc::{self, msg_send, sel, sel_impl, class};
}
};
@@ -4396,6 +4678,9 @@ pub mod utils {
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]
@@ -4405,12 +4690,12 @@ pub mod utils {
#[inline]
pub unsafe fn as_ref(&self) -> &T {
- ::#prefix::mem::transmute(self)
+ #transmute
}
#[inline]
pub unsafe fn as_mut(&mut self) -> &mut T {
- ::#prefix::mem::transmute(self)
+ #transmute
}
}
};
@@ -4505,6 +4790,13 @@ pub mod utils {
::#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]
@@ -4524,12 +4816,12 @@ pub mod utils {
#[inline]
pub unsafe fn as_slice(&self, len: usize) -> &[T] {
- ::#prefix::slice::from_raw_parts(self.as_ptr(), len)
+ #from_raw_parts
}
#[inline]
pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
- ::#prefix::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
+ #from_raw_parts_mut
}
}
};
@@ -4618,21 +4910,52 @@ pub mod utils {
})
}
- pub fn fnsig_return_ty(
+ fn fnsig_return_ty_internal(
ctx: &BindgenContext,
sig: &FunctionSig,
+ include_arrow: bool,
) -> proc_macro2::TokenStream {
- let return_item = ctx.resolve_item(sig.return_type());
- if let TypeKind::Void = *return_item.kind().expect_type().kind() {
- quote! {}
+ if sig.is_divergent() {
+ return if include_arrow {
+ quote! { -> ! }
+ } else {
+ quote! { ! }
+ };
+ }
+
+ let canonical_type_kind = sig
+ .return_type()
+ .into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(ctx)
+ .kind()
+ .expect_type()
+ .kind();
+
+ if let TypeKind::Void = canonical_type_kind {
+ return if include_arrow {
+ quote! {}
+ } else {
+ quote! { () }
+ };
+ }
+
+ let ret_ty = sig.return_type().to_rust_ty_or_opaque(ctx, &());
+ if include_arrow {
+ quote! { -> #ret_ty }
} else {
- let ret_ty = return_item.to_rust_ty_or_opaque(ctx, &());
- quote! {
- -> #ret_ty
- }
+ ret_ty
}
}
+ pub fn fnsig_return_ty(
+ ctx: &BindgenContext,
+ sig: &FunctionSig,
+ ) -> proc_macro2::TokenStream {
+ fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true)
+ }
+
pub fn fnsig_arguments(
ctx: &BindgenContext,
sig: &FunctionSig,
@@ -4745,14 +5068,9 @@ pub mod utils {
arg_item.to_rust_ty_or_opaque(ctx, &())
});
- let return_item = ctx.resolve_item(sig.return_type());
- let ret_ty =
- if let TypeKind::Void = *return_item.kind().expect_type().kind() {
- quote! { () }
- } else {
- return_item.to_rust_ty_or_opaque(ctx, &())
- };
-
+ let ret_ty = fnsig_return_ty_internal(
+ ctx, sig, /* include_arrow = */ false,
+ );
quote! {
*const ::block::Block<(#(#args,)*), #ret_ty>
}
@@ -4761,10 +5079,10 @@ pub mod utils {
// Returns true if `canonical_name` will end up as `mangled_name` at the
// machine code level, i.e. after LLVM has applied any target specific
// mangling.
- pub fn names_will_be_identical_after_mangling(
+ pub(crate) fn names_will_be_identical_after_mangling(
canonical_name: &str,
mangled_name: &str,
- call_conv: Option<Abi>,
+ 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.
@@ -4777,13 +5095,13 @@ pub mod utils {
let mangled_name = mangled_name.as_bytes();
let (mangling_prefix, expect_suffix) = match call_conv {
- Some(Abi::C) |
+ Some(ClangAbi::Known(Abi::C)) |
// None is the case for global variables
None => {
(b'_', false)
}
- Some(Abi::Stdcall) => (b'_', true),
- Some(Abi::Fastcall) => (b'@', true),
+ 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
diff --git a/codegen/postprocessing/merge_extern_blocks.rs b/codegen/postprocessing/merge_extern_blocks.rs
new file mode 100644
index 0000000..05e7e9e
--- /dev/null
+++ b/codegen/postprocessing/merge_extern_blocks.rs
@@ -0,0 +1,66 @@
+use syn::{
+ visit_mut::{visit_item_mod_mut, VisitMut},
+ Item, ItemForeignMod, ItemMod,
+};
+
+pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) {
+ Visitor.visit_item_mod_mut(item_mod)
+}
+
+struct Visitor;
+
+impl VisitMut for Visitor {
+ fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
+ if let Some((_, ref mut items)) = item_mod.content {
+ // 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,
+ 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,
+ 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));
+ }
+ }
+
+ visit_item_mod_mut(self, item_mod)
+ }
+}
diff --git a/codegen/postprocessing/mod.rs b/codegen/postprocessing/mod.rs
new file mode 100644
index 0000000..1d5a498
--- /dev/null
+++ b/codegen/postprocessing/mod.rs
@@ -0,0 +1,66 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::{parse2, ItemMod};
+
+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 ItemMod),
+}
+
+// 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: |item_mod| $pass(item_mod),
+ }
+ };
+}
+
+const PASSES: &[PostProcessingPass] =
+ &[pass!(merge_extern_blocks), pass!(sort_semantically)];
+
+pub(crate) fn postprocessing(
+ items: Vec<TokenStream>,
+ options: &BindgenOptions,
+) -> TokenStream {
+ let require_syn = PASSES.iter().any(|pass| (pass.should_run)(options));
+ if !require_syn {
+ return items.into_iter().collect();
+ }
+ let module_wrapped_tokens =
+ quote!(mod wrapper_for_postprocessing_hack { #( #items )* });
+
+ // This syn business is a hack, for now. This means that we are re-parsing already
+ // generated code using `syn` (as opposed to `quote`) because `syn` provides us more
+ // control over the elements.
+ // One caveat is that some of the items coming from `quote`d output might have
+ // multiple items within them. Hence, we have to wrap the incoming in a `mod`.
+ // The `unwrap` here is deliberate because bindgen should generate valid rust items at all
+ // times.
+ let mut item_mod = parse2::<ItemMod>(module_wrapped_tokens).unwrap();
+
+ for pass in PASSES {
+ if (pass.should_run)(options) {
+ (pass.run)(&mut item_mod);
+ }
+ }
+
+ let synful_items = item_mod
+ .content
+ .map(|(_, items)| items)
+ .unwrap_or_default()
+ .into_iter()
+ .map(|item| item.into_token_stream());
+
+ quote! { #( #synful_items )* }
+}
diff --git a/codegen/postprocessing/sort_semantically.rs b/codegen/postprocessing/sort_semantically.rs
new file mode 100644
index 0000000..4f23ab7
--- /dev/null
+++ b/codegen/postprocessing/sort_semantically.rs
@@ -0,0 +1,38 @@
+use syn::{
+ visit_mut::{visit_item_mod_mut, VisitMut},
+ Item, ItemMod,
+};
+
+pub(super) fn sort_semantically(item_mod: &mut ItemMod) {
+ Visitor.visit_item_mod_mut(item_mod)
+}
+
+struct Visitor;
+
+impl VisitMut for Visitor {
+ fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
+ if let Some((_, ref mut items)) = item_mod.content {
+ items.sort_by_key(|item| match item {
+ Item::Type(_) => 0,
+ Item::Struct(_) => 1,
+ Item::Const(_) => 2,
+ Item::Fn(_) => 3,
+ Item::Enum(_) => 4,
+ Item::Union(_) => 5,
+ Item::Static(_) => 6,
+ Item::Trait(_) => 7,
+ Item::TraitAlias(_) => 8,
+ Item::Impl(_) => 9,
+ Item::Mod(_) => 10,
+ Item::Use(_) => 11,
+ Item::Verbatim(_) => 12,
+ Item::ExternCrate(_) => 13,
+ Item::ForeignMod(_) => 14,
+ Item::Macro(_) => 15,
+ Item::Macro2(_) => 16,
+ _ => 18,
+ });
+ }
+ visit_item_mod_mut(self, item_mod)
+ }
+}
diff --git a/codegen/serialize.rs b/codegen/serialize.rs
new file mode 100644
index 0000000..217098e
--- /dev/null
+++ b/codegen/serialize.rs
@@ -0,0 +1,356 @@
+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;
+
+fn get_loc(item: &Item) -> String {
+ item.location()
+ .map(|x| x.to_string())
+ .unwrap_or_else(|| "unknown".to_owned())
+}
+
+pub(crate) 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 = ();
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ (): Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ match self.kind() {
+ ItemKind::Function(func) => {
+ func.serialize(ctx, self, stack, writer)
+ }
+ kind => {
+ return Err(CodegenError::Serialize {
+ msg: format!("Cannot serialize item kind {:?}", kind),
+ loc: get_loc(self),
+ });
+ }
+ }
+ }
+}
+
+impl<'a> CSerialize<'a> for Function {
+ type Extra = &'a Item;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ item: 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!(),
+ };
+
+ let name = self.name();
+
+ // Function argoments stored as `(name, type_id)` tuples.
+ let args = {
+ let mut count = 0;
+
+ signature
+ .argument_types()
+ .iter()
+ .cloned()
+ .map(|(opt_name, type_id)| {
+ (
+ 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_ty = signature.return_type();
+
+ // Write `ret_ty wrap_name(args) asm("wrap_name");`
+ ret_ty.serialize(ctx, (), stack, writer)?;
+ write!(writer, " {}(", wrap_name)?;
+ 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)
+ },
+ )?;
+ }
+ writeln!(writer, ") asm(\"{}\");", wrap_name)?;
+
+ // Write `ret_ty wrap_name(args) { return name(arg_names)' }`
+ ret_ty.serialize(ctx, (), stack, writer)?;
+ write!(writer, " {}(", wrap_name)?;
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), _, buf| {
+ type_id.serialize(ctx, (), &mut vec![name.clone()], buf)
+ },
+ )?;
+ write!(writer, ") {{ return {}(", name)?;
+ serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| {
+ write!(buf, "{}", name).map_err(From::from)
+ })?;
+ 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::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::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, ")")?;
+
+ write!(writer, " (")?;
+ serialize_sep(
+ ", ",
+ signature.argument_types().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)?,
+ };
+ }
+ 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_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/src/codegen/struct_layout.rs b/codegen/struct_layout.rs
index 657be0b..ddac1b0 100644
--- a/src/codegen/struct_layout.rs
+++ b/codegen/struct_layout.rs
@@ -20,6 +20,7 @@ pub struct StructLayoutTracker<'a> {
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>,
@@ -90,8 +91,8 @@ impl<'a> StructLayoutTracker<'a> {
) -> Self {
let known_type_layout = ty.layout(ctx);
let is_packed = comp.is_packed(ctx, known_type_layout.as_ref());
- let is_rust_union = comp.is_union() &&
- comp.can_be_rust_union(ctx, known_type_layout.as_ref());
+ let (is_rust_union, can_copy_union_fields) =
+ comp.is_rust_union(ctx, known_type_layout.as_ref(), name);
StructLayoutTracker {
name,
ctx,
@@ -99,6 +100,7 @@ impl<'a> StructLayoutTracker<'a> {
is_packed,
known_type_layout,
is_rust_union,
+ can_copy_union_fields,
latest_offset: 0,
padding_count: 0,
latest_field_layout: None,
@@ -107,6 +109,10 @@ impl<'a> StructLayoutTracker<'a> {
}
}
+ pub fn can_copy_union_fields(&self) -> bool {
+ self.can_copy_union_fields
+ }
+
pub fn is_rust_union(&self) -> bool {
self.is_rust_union
}
diff --git a/csmith-fuzzing/README.md b/csmith-fuzzing/README.md
deleted file mode 100644
index cdd6d08..0000000
--- a/csmith-fuzzing/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# Fuzzing `bindgen` with `csmith`
-
-[`csmith`][csmith] generates random C and C++ programs that can be used as test
-cases for compilers. When testing `bindgen` with `csmith`, we interpret the
-generated programs as header files, and emit Rust bindings to them. If `bindgen`
-panics, the emitted bindings won't compile with `rustc`, or the generated layout
-tests in the bindings fail, then we report an issue containing the test case!
-
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-
-
-- [Prerequisites](#prerequisites)
-- [Running the Fuzzer](#running-the-fuzzer)
-- [Reporting Issues](#reporting-issues)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Prerequisites
-
-Requires `python3`, `csmith`, and `creduce` to be in `$PATH`.
-
-Many OS package managers have `csmith` and `creduce` packages:
-
-```
-$ sudo apt install csmith creduce
-$ brew install csmith creduce
-$ # Etc...
-```
-
-## Running the Fuzzer
-
-Run `csmith` and test `bindgen` on the generated test cases with this command:
-
-```
-$ ./driver.py
-```
-
-The driver will keep running until it encounters an error in `bindgen`.
-
-Each invocation of `./driver.py` will use its own temporary directories, so
-running it in multiple terminals in parallel is supported.
-
-`csmith` is run with `--no-checksum --nomain --max-block-size 1
---max-block-depth 1` which disables the `main` function, and makes function
-bodies as simple as possible as `bindgen` does not care about them, but they
-cannot be completely disabled in `csmith`. Run `csmith --help` to see what
-exactly those options do.
-
-## Reporting Issues
-
-Once the fuzz driver finds a test case that causes some kind of error in
-`bindgen` or its emitted bindings, it is helpful to
-[run C-Reduce on the test case][creducing] to remove the parts that are
-irrelevant to reproducing the error. This is ***very*** helpful for the folks
-who further investigate the issue and come up with a fix!
-
-Additionally, mention that you discovered the issue via `csmith` and we will add
-the `A-csmith` label. You can find all the issues discovered with `csmith`, and
-related to fuzzing with `csmith`, by looking up
-[all issues tagged with the `A-csmith` label][csmith-issues].
-
-[csmith]: https://github.com/csmith-project/csmith
-[creducing]: ../CONTRIBUTING.md#using-creduce-to-minimize-test-cases
-[csmith-issues]: https://github.com/rust-lang/rust-bindgen/issues?q=label%3AA-csmith
diff --git a/src/deps.rs b/deps.rs
index 479c396..987225b 100644
--- a/src/deps.rs
+++ b/deps.rs
@@ -1,7 +1,7 @@
/// Generating build depfiles from parsed bindings.
use std::{collections::BTreeSet, path::PathBuf};
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub(crate) struct DepfileSpec {
pub output_module: String,
pub depfile_path: PathBuf,
diff --git a/src/extra_assertions.rs b/extra_assertions.rs
index 0888bf3..0888bf3 100644
--- a/src/extra_assertions.rs
+++ b/extra_assertions.rs
diff --git a/src/features.rs b/features.rs
index a786f07..4fee5d6 100644
--- a/src/features.rs
+++ b/features.rs
@@ -2,6 +2,7 @@
#![deny(missing_docs)]
#![deny(unused_extern_crates)]
+#![allow(deprecated)]
use std::io;
use std::str::FromStr;
@@ -86,35 +87,35 @@ macro_rules! rust_target_base {
( $x_macro:ident ) => {
$x_macro!(
/// Rust stable 1.0
- => Stable_1_0 => 1.0;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_0 => 1.0;
/// Rust stable 1.17
/// * Static lifetime elision ([RFC 1623](https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md))
- => Stable_1_17 => 1.17;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_17 => 1.17;
/// Rust stable 1.19
/// * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
- => Stable_1_19 => 1.19;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_19 => 1.19;
/// Rust stable 1.20
/// * Associated constants ([PR](https://github.com/rust-lang/rust/pull/42809))
- => Stable_1_20 => 1.20;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_20 => 1.20;
/// Rust stable 1.21
/// * Builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690))
- => Stable_1_21 => 1.21;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_21 => 1.21;
/// Rust stable 1.25
/// * `repr(align)` ([PR](https://github.com/rust-lang/rust/pull/47006))
- => Stable_1_25 => 1.25;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_25 => 1.25;
/// Rust stable 1.26
/// * [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html)
- => Stable_1_26 => 1.26;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_26 => 1.26;
/// Rust stable 1.27
/// * `must_use` attribute on functions ([PR](https://github.com/rust-lang/rust/pull/48925))
- => Stable_1_27 => 1.27;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_27 => 1.27;
/// Rust stable 1.28
/// * `repr(transparent)` ([PR](https://github.com/rust-lang/rust/pull/51562))
- => Stable_1_28 => 1.28;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_28 => 1.28;
/// Rust stable 1.30
/// * `const fn` support for limited cases ([PR](https://github.com/rust-lang/rust/pull/54835/)
/// * [c_void available in core](https://doc.rust-lang.org/core/ffi/enum.c_void.html)
- => Stable_1_30 => 1.30;
+ #[deprecated = "This rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues"] => Stable_1_30 => 1.30;
/// Rust stable 1.33
/// * repr(packed(N)) ([PR](https://github.com/rust-lang/rust/pull/57049))
=> Stable_1_33 => 1.33;
@@ -127,8 +128,13 @@ macro_rules! rust_target_base {
/// Rust stable 1.47
/// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060))
=> Stable_1_47 => 1.47;
+ /// Rust stable 1.64
+ /// * `core_ffi_c` ([Tracking issue](https://github.com/rust-lang/rust/issues/94501))
+ => Stable_1_64 => 1.64;
/// Nightly rust
/// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
+ /// * `vectorcall` calling convention (no tracking issue)
+ /// * `c_unwind` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/74990))
=> Nightly => nightly;
);
}
@@ -138,7 +144,7 @@ rust_target_base!(rust_target_def);
rust_target_base!(rust_target_values_def);
/// Latest stable release of Rust
-pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_47;
+pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_64;
/// Create RustFeatures struct definition, new(), and a getter for each field
macro_rules! rust_feature_def {
@@ -232,8 +238,13 @@ rust_feature_def!(
Stable_1_47 {
=> larger_arrays;
}
+ Stable_1_64 {
+ => core_ffi_c;
+ }
Nightly {
=> thiscall_abi;
+ => vectorcall_abi;
+ => c_unwind_abi;
}
);
@@ -259,7 +270,8 @@ mod test {
!f_1_0.associated_const &&
!f_1_0.builtin_clone_impls &&
!f_1_0.repr_align &&
- !f_1_0.thiscall_abi
+ !f_1_0.thiscall_abi &&
+ !f_1_0.vectorcall_abi
);
let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
assert!(
@@ -269,7 +281,8 @@ mod test {
f_1_21.associated_const &&
f_1_21.builtin_clone_impls &&
!f_1_21.repr_align &&
- !f_1_21.thiscall_abi
+ !f_1_21.thiscall_abi &&
+ !f_1_21.vectorcall_abi
);
let f_nightly = RustFeatures::from(RustTarget::Nightly);
assert!(
@@ -280,7 +293,9 @@ mod test {
f_nightly.builtin_clone_impls &&
f_nightly.maybe_uninit &&
f_nightly.repr_align &&
- f_nightly.thiscall_abi
+ f_nightly.thiscall_abi &&
+ f_nightly.vectorcall_abi &&
+ f_nightly.c_unwind_abi
);
}
diff --git a/src/ir/analysis/derive.rs b/ir/analysis/derive.rs
index f63458e..d888cd5 100644
--- a/src/ir/analysis/derive.rs
+++ b/ir/analysis/derive.rs
@@ -485,11 +485,11 @@ impl DeriveTrait {
fn consider_edge_tmpl_inst(&self) -> EdgePredicate {
match self {
DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
- _ => |kind| match kind {
- EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration => {
- true
- }
- _ => false,
+ _ => |kind| {
+ matches!(
+ kind,
+ EdgeKind::TemplateArgument | EdgeKind::TemplateDeclaration
+ )
},
}
}
diff --git a/src/ir/analysis/has_destructor.rs b/ir/analysis/has_destructor.rs
index 74fd73d..74fd73d 100644
--- a/src/ir/analysis/has_destructor.rs
+++ b/ir/analysis/has_destructor.rs
diff --git a/src/ir/analysis/has_float.rs b/ir/analysis/has_float.rs
index bbf2126..bbf2126 100644
--- a/src/ir/analysis/has_float.rs
+++ b/ir/analysis/has_float.rs
diff --git a/src/ir/analysis/has_type_param_in_array.rs b/ir/analysis/has_type_param_in_array.rs
index aa52304..aa52304 100644
--- a/src/ir/analysis/has_type_param_in_array.rs
+++ b/ir/analysis/has_type_param_in_array.rs
diff --git a/src/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs
index 8ac47a6..8ac47a6 100644
--- a/src/ir/analysis/has_vtable.rs
+++ b/ir/analysis/has_vtable.rs
diff --git a/src/ir/analysis/mod.rs b/ir/analysis/mod.rs
index eb9a1c0..40dfc6d 100644
--- a/src/ir/analysis/mod.rs
+++ b/ir/analysis/mod.rs
@@ -281,9 +281,13 @@ mod tests {
fn reverse(&self) -> Graph {
let mut reversed = Graph::default();
for (node, edges) in self.0.iter() {
- reversed.0.entry(*node).or_insert(vec![]);
+ reversed.0.entry(*node).or_insert_with(Vec::new);
for referent in edges.iter() {
- reversed.0.entry(*referent).or_insert(vec![]).push(*node);
+ reversed
+ .0
+ .entry(*referent)
+ .or_insert_with(Vec::new)
+ .push(*node);
}
}
reversed
@@ -306,8 +310,8 @@ mod tests {
let reversed = graph.reverse();
ReachableFrom {
reachable: Default::default(),
- graph: graph,
- reversed: reversed,
+ graph,
+ reversed,
}
}
@@ -328,7 +332,7 @@ mod tests {
let original_size = self
.reachable
.entry(node)
- .or_insert(HashSet::default())
+ .or_insert_with(HashSet::default)
.len();
for sub_node in self.graph.0[&node].iter() {
@@ -337,7 +341,7 @@ mod tests {
let sub_reachable = self
.reachable
.entry(*sub_node)
- .or_insert(HashSet::default())
+ .or_insert_with(HashSet::default)
.clone();
for transitive in sub_reachable {
diff --git a/src/ir/analysis/sizedness.rs b/ir/analysis/sizedness.rs
index 251c374..251c374 100644
--- a/src/ir/analysis/sizedness.rs
+++ b/ir/analysis/sizedness.rs
diff --git a/src/ir/analysis/template_params.rs b/ir/analysis/template_params.rs
index e88b774..f4f0c59 100644
--- a/src/ir/analysis/template_params.rs
+++ b/ir/analysis/template_params.rs
@@ -424,8 +424,7 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
// generic template parameters are used.
let item_kind =
ctx.resolve_item(item).as_type().map(|ty| ty.kind());
- if let Some(&TypeKind::TemplateInstantiation(ref inst)) = item_kind
- {
+ if let Some(TypeKind::TemplateInstantiation(inst)) = item_kind {
let decl = ctx.resolve_type(inst.template_definition());
let args = inst.template_arguments();
@@ -540,7 +539,7 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
}
// Template instantiations only use their template arguments if the
// template definition uses the corresponding template parameter.
- Some(&TypeKind::TemplateInstantiation(ref inst)) => {
+ Some(TypeKind::TemplateInstantiation(inst)) => {
if self
.allowlisted_items
.contains(&inst.template_definition().into())
diff --git a/src/ir/annotations.rs b/ir/annotations.rs
index 9bcda50..288c11e 100644
--- a/src/ir/annotations.rs
+++ b/ir/annotations.rs
@@ -7,7 +7,7 @@
use crate::clang;
/// What kind of accessor should we provide for a field?
-#[derive(Copy, PartialEq, Clone, Debug)]
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum FieldAccessorKind {
/// No accessor.
None,
@@ -25,7 +25,7 @@ pub enum FieldAccessorKind {
/// documentation:
///
/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
-#[derive(Default, Clone, PartialEq, Debug)]
+#[derive(Default, Clone, PartialEq, Eq, Debug)]
pub struct Annotations {
/// Whether this item is marked as opaque. Only applies to types.
opaque: bool,
diff --git a/src/ir/comment.rs b/ir/comment.rs
index c96e3eb..3eb17aa 100644
--- a/src/ir/comment.rs
+++ b/ir/comment.rs
@@ -12,10 +12,10 @@ enum Kind {
}
/// Preprocesses a C/C++ comment so that it is a valid Rust comment.
-pub fn preprocess(comment: &str, indent: usize) -> String {
+pub fn preprocess(comment: &str) -> String {
match self::kind(comment) {
- Some(Kind::SingleLines) => preprocess_single_lines(comment, indent),
- Some(Kind::MultiLine) => preprocess_multi_line(comment, indent),
+ Some(Kind::SingleLines) => preprocess_single_lines(comment),
+ Some(Kind::MultiLine) => preprocess_multi_line(comment),
None => comment.to_owned(),
}
}
@@ -31,56 +31,34 @@ fn kind(comment: &str) -> Option<Kind> {
}
}
-fn make_indent(indent: usize) -> String {
- const RUST_INDENTATION: usize = 4;
- " ".repeat(indent * RUST_INDENTATION)
-}
-
/// Preprocesses multiple single line comments.
///
/// Handles lines starting with both `//` and `///`.
-fn preprocess_single_lines(comment: &str, indent: usize) -> String {
+fn preprocess_single_lines(comment: &str) -> String {
debug_assert!(comment.starts_with("//"), "comment is not single line");
- let indent = make_indent(indent);
- let mut is_first = true;
let lines: Vec<_> = comment
.lines()
.map(|l| l.trim().trim_start_matches('/'))
- .map(|l| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, l)
- })
.collect();
lines.join("\n")
}
-fn preprocess_multi_line(comment: &str, indent: usize) -> String {
+fn preprocess_multi_line(comment: &str) -> String {
let comment = comment
.trim_start_matches('/')
.trim_end_matches('/')
.trim_end_matches('*');
- let indent = make_indent(indent);
// Strip any potential `*` characters preceding each line.
- let mut is_first = true;
let mut lines: Vec<_> = comment
.lines()
.map(|line| line.trim().trim_start_matches('*').trim_start_matches('!'))
.skip_while(|line| line.trim().is_empty()) // Skip the first empty lines.
- .map(|line| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, line)
- })
.collect();
// Remove the trailing line corresponding to the `*/`.
- if lines
- .last()
- .map_or(false, |l| l.trim().is_empty() || l.trim() == "///")
- {
+ if lines.last().map_or(false, |l| l.trim().is_empty()) {
lines.pop();
}
@@ -99,21 +77,24 @@ mod test {
#[test]
fn processes_single_lines_correctly() {
- assert_eq!(preprocess("/// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
+ 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 */", 0),
- "/// hello\n/// world\n/// foo"
+ preprocess("/** hello \n * world \n * foo \n */"),
+ " hello\n world\n foo"
);
assert_eq!(
- preprocess("/**\nhello\n*world\n*foo\n*/", 0),
- "///hello\n///world\n///foo"
+ preprocess("/**\nhello\n*world\n*foo\n*/"),
+ "hello\nworld\nfoo"
);
}
}
diff --git a/src/ir/comp.rs b/ir/comp.rs
index a221e52..18a4291 100644
--- a/src/ir/comp.rs
+++ b/ir/comp.rs
@@ -12,15 +12,16 @@ use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
use crate::clang;
use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2};
use crate::ir::derive::CanDeriveCopy;
-use crate::parse::{ClangItemParser, ParseError};
+use crate::parse::ParseError;
use crate::HashMap;
+use crate::NonCopyUnionStyle;
use peeking_take_while::PeekableExt;
use std::cmp;
use std::io;
use std::mem;
/// The kind of compound type.
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompKind {
/// A struct.
Struct,
@@ -29,7 +30,7 @@ pub enum CompKind {
}
/// The kind of C++ method.
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MethodKind {
/// A constructor. We represent it as method for convenience, to avoid code
/// duplication.
@@ -55,12 +56,10 @@ pub enum MethodKind {
impl MethodKind {
/// Is this a destructor method?
pub fn is_destructor(&self) -> bool {
- match *self {
- MethodKind::Destructor | MethodKind::VirtualDestructor { .. } => {
- true
- }
- _ => false,
- }
+ matches!(
+ *self,
+ MethodKind::Destructor | MethodKind::VirtualDestructor { .. }
+ )
}
/// Is this a pure virtual method?
@@ -1045,6 +1044,11 @@ pub struct CompInfo {
/// 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,
@@ -1078,6 +1082,7 @@ impl CompInfo {
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,
@@ -1317,7 +1322,21 @@ impl CompInfo {
}
}
- let bit_width = cur.bit_width();
+ 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,
@@ -1403,8 +1422,7 @@ impl CompInfo {
// A declaration of an union or a struct without name
// could also be an unnamed field, unfortunately.
- if cur.spelling().is_empty() &&
- cur.kind() != CXCursor_EnumDecl
+ if cur.is_anonymous() && cur.kind() != CXCursor_EnumDecl
{
let ty = cur.cur_type();
let public = cur.public_accessible();
@@ -1662,21 +1680,37 @@ impl CompInfo {
///
/// Requirements:
/// 1. Current RustTarget allows for `untagged_union`
- /// 2. Each field can derive `Copy`
+ /// 2. Each field can derive `Copy` or we use ManuallyDrop.
/// 3. It's not zero-sized.
- pub fn can_be_rust_union(
+ ///
+ /// Second boolean returns whether all fields can be copied (and thus
+ /// ManuallyDrop is not needed).
+ pub fn is_rust_union(
&self,
ctx: &BindgenContext,
layout: Option<&Layout>,
- ) -> bool {
+ name: &str,
+ ) -> (bool, bool) {
+ if !self.is_union() {
+ return (false, false);
+ }
+
if !ctx.options().rust_features().untagged_union {
- return false;
+ return (false, false);
}
if self.is_forward_declaration() {
- return false;
+ 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)
@@ -1684,15 +1718,15 @@ impl CompInfo {
Field::Bitfields(_) => true,
});
- if !all_can_copy {
- return false;
+ if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper {
+ return (false, false);
}
if layout.map_or(false, |l| l.size == 0) {
- return false;
+ return (false, false);
}
- true
+ (true, all_can_copy)
}
}
@@ -1753,7 +1787,9 @@ 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 {
+ if self.has_non_type_template_params ||
+ self.has_unevaluable_bit_field_width
+ {
return true;
}
diff --git a/src/ir/context.rs b/ir/context.rs
index a9e19fb..b693a70 100644
--- a/src/ir/context.rs
+++ b/ir/context.rs
@@ -19,14 +19,14 @@ use super::module::{Module, ModuleKind};
use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
-use crate::callbacks::ParseCallbacks;
use crate::clang::{self, Cursor};
-use crate::parse::ClangItemParser;
+use crate::codegen::CodegenError;
use crate::BindgenOptions;
use crate::{Entry, HashMap, HashSet};
use cexpr;
use clang_sys;
-use proc_macro2::{Ident, Span};
+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};
@@ -364,14 +364,11 @@ pub struct BindgenContext {
in_codegen: bool,
- /// The clang index for parsing.
- index: clang::Index,
-
/// The translation unit for parsing.
translation_unit: clang::TranslationUnit,
/// Target information that can be useful for some stuff.
- target_info: Option<clang::TargetInfo>,
+ target_info: clang::TargetInfo,
/// The options given by the user via cli or other medium.
options: BindgenOptions,
@@ -402,6 +399,22 @@ pub struct BindgenContext {
/// 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`
@@ -420,12 +433,6 @@ pub struct BindgenContext {
/// 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 copy in array.
- ///
- /// This is populated when we enter codegen by `compute_cannot_derive_copy`
- /// and is always `None` before that and `Some` after.
- cannot_derive_copy_in_array: Option<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`
@@ -468,17 +475,15 @@ pub struct BindgenContext {
/// Populated when we enter codegen by `compute_has_float`; always `None`
/// before that and `Some` after.
has_float: Option<HashSet<ItemId>>,
+
+ /// The set of warnings raised during binding generation.
+ warnings: Vec<String>,
}
/// A traversal of allowlisted items.
struct AllowlistedItemsTraversal<'ctx> {
ctx: &'ctx BindgenContext,
- traversal: ItemTraversal<
- 'ctx,
- ItemSet,
- Vec<ItemId>,
- for<'a> fn(&'a BindgenContext, Edge) -> bool,
- >,
+ traversal: ItemTraversal<'ctx, ItemSet, Vec<ItemId>>,
}
impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> {
@@ -516,7 +521,10 @@ impl<'ctx> AllowlistedItemsTraversal<'ctx> {
impl BindgenContext {
/// Construct the context for the given `options`.
- pub(crate) fn new(options: BindgenOptions) -> Self {
+ 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
@@ -533,7 +541,7 @@ impl BindgenContext {
&index,
"",
&options.clang_args,
- &options.input_unsaved_files,
+ input_unsaved_files,
parse_options,
).expect("libclang error; possible causes include:
- Invalid flag syntax
@@ -549,11 +557,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let root_module_id = root_module.id().as_module_id_unchecked();
// depfiles need to include the explicitly listed headers too
- let mut deps = BTreeSet::default();
- if let Some(filename) = &options.input_header {
- deps.insert(filename.clone());
- }
- deps.extend(options.extra_input_headers.iter().cloned());
+ let deps = options.input_headers.iter().cloned().collect();
BindgenContext {
items: vec![Some(root_module)],
@@ -569,7 +573,6 @@ If you encounter an error missing from this list, please file an issue or a PR!"
replacements: Default::default(),
collected_typerefs: false,
in_codegen: false,
- index,
translation_unit,
target_info,
options,
@@ -579,10 +582,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
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_copy_in_array: None,
cannot_derive_hash: None,
cannot_derive_partialeq_or_partialord: None,
sizedness: None,
@@ -590,15 +593,13 @@ If you encounter an error missing from this list, please file an issue or a PR!"
have_destructor: None,
has_type_param_in_array: None,
has_float: None,
+ warnings: Vec::new(),
}
}
/// Returns `true` if the target architecture is wasm32
pub fn is_target_wasm32(&self) -> bool {
- match self.target_info {
- Some(ref ti) => ti.triple.starts_with("wasm32-"),
- None => false,
- }
+ self.target_info.triple.starts_with("wasm32-")
}
/// Creates a timer for the current bindgen phase. If time_phases is `true`,
@@ -611,10 +612,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
/// Returns the pointer width to use for the target for the current
/// translation.
pub fn target_pointer_size(&self) -> usize {
- if let Some(ref ti) = self.target_info {
- return ti.pointer_width / 8;
- }
- mem::size_of::<*mut ()>()
+ self.target_info.pointer_width / 8
}
/// Get the stack of partially parsed types that we are in the middle of
@@ -638,15 +636,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
)
}
- /// Get the user-provided callbacks by reference, if any.
- pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> {
- self.options().parse_callbacks.as_deref()
- }
-
/// Add another path to the set of included files.
pub fn include_file(&mut self, filename: String) {
- if let Some(cbs) = self.parse_callbacks() {
- cbs.include_file(&filename);
+ for cb in &self.options().parse_callbacks {
+ cb.include_file(&filename);
}
self.deps.insert(filename);
}
@@ -838,7 +831,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
name.contains('$') ||
matches!(
name,
- "abstract" | "alignof" | "as" | "async" | "become" |
+ "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" |
@@ -853,9 +846,9 @@ If you encounter an error missing from this list, please file an issue or a PR!"
)
{
let mut s = name.to_owned();
- s = s.replace("@", "_");
- s = s.replace("?", "_");
- s = s.replace("$", "_");
+ s = s.replace('@', "_");
+ s = s.replace('?', "_");
+ s = s.replace('$', "_");
s.push('_');
return Cow::Owned(s);
}
@@ -1151,9 +1144,12 @@ If you encounter an error missing from this list, please file an issue or a PR!"
/// Enter the code generation phase, invoke the given callback `cb`, and
/// leave the code generation phase.
- pub(crate) fn gen<F, Out>(mut self, cb: F) -> (Out, BindgenOptions)
+ pub(crate) fn gen<F, Out>(
+ mut self,
+ cb: F,
+ ) -> Result<(Out, BindgenOptions, Vec<String>), CodegenError>
where
- F: FnOnce(&Self) -> Out,
+ F: FnOnce(&Self) -> Result<Out, CodegenError>,
{
self.in_codegen = true;
@@ -1179,6 +1175,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
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();
@@ -1187,8 +1184,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.compute_cannot_derive_hash();
self.compute_cannot_derive_partialord_partialeq_or_eq();
- let ret = cb(&self);
- (ret, self.options)
+ let ret = cb(&self)?;
+ Ok((ret, self.options, self.warnings))
}
/// When the `testing_only_extra_assertions` feature is enabled, this
@@ -2092,7 +2089,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.in_codegen_phase(),
"You're not supposed to call this yet"
);
- self.options.opaque_types.matches(&path[1..].join("::"))
+ self.options.opaque_types.matches(path[1..].join("::"))
}
/// Get the options used to configure this bindgen context.
@@ -2119,13 +2116,18 @@ If you encounter an error missing from this list, please file an issue or a PR!"
}
let mut kind = ModuleKind::Normal;
- let mut found_namespace_keyword = false;
+ let mut looking_for_name = false;
for token in cursor.tokens().iter() {
match token.spelling() {
b"inline" => {
- assert!(!found_namespace_keyword);
- assert!(kind != ModuleKind::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 { }
@@ -2134,45 +2136,39 @@ If you encounter an error missing from this list, please file an issue or a PR!"
// but the tokenization of the second begins with the double
// colon. That's ok, so we only need to handle the weird
// tokenization here.
- //
- // Fortunately enough, inline nested namespace specifiers aren't
- // a thing, and are invalid C++ :)
b"namespace" | b"::" => {
- found_namespace_keyword = true;
+ looking_for_name = true;
}
b"{" => {
- assert!(found_namespace_keyword);
+ // This should be an anonymous namespace.
+ assert!(looking_for_name);
break;
}
- name if found_namespace_keyword => {
- if module_name.is_none() {
- module_name =
- Some(String::from_utf8_lossy(name).into_owned());
+ 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
+ );
}
- break;
- }
- spelling if !found_namespace_keyword => {
- // This is _likely_, but not certainly, a macro that's been placed just before
- // the namespace keyword. Unfortunately, clang tokens don't let us easily see
- // through the ifdef tokens, so we don't know what this token should really be.
- // Instead of panicking though, we warn the user that we assumed the token was
- // blank, and then move on.
- //
- // See also https://github.com/rust-lang/rust-bindgen/issues/1676.
- warn!(
- "Ignored unknown namespace prefix '{}' at {:?} in {:?}",
- String::from_utf8_lossy(spelling),
- token,
- cursor
- );
- }
- spelling => {
- panic!(
- "Unknown token '{}' while processing namespace at {:?} in {:?}",
- String::from_utf8_lossy(spelling),
- token,
- cursor
- );
}
}
}
@@ -2257,32 +2253,40 @@ If you encounter an error missing from this list, please file an issue or a PR!"
.or_insert_with(|| {
item.expect_type()
.name()
- .and_then(|name| match self.options.parse_callbacks {
- Some(ref cb) => cb.blocklisted_type_implements_trait(
- name,
- derive_trait,
- ),
- // Sized integer types from <stdint.h> get mapped to Rust primitive
- // types regardless of whether they are blocklisted, so ensure that
- // standard traits are considered derivable for them too.
- None => match name {
- "int8_t" | "uint8_t" | "int16_t" | "uint16_t" |
- "int32_t" | "uint32_t" | "int64_t" |
- "uint64_t" | "uintptr_t" | "intptr_t" |
- "ptrdiff_t" => Some(CanDerive::Yes),
- "size_t" if self.options.size_t_is_usize => {
+ .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)
}
- "ssize_t" if self.options.size_t_is_usize => {
- Some(CanDerive::Yes)
- }
- _ => 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 fn is_stdint_type(&self, name: &str) -> bool {
+ match name {
+ "int8_t" | "uint8_t" | "int16_t" | "uint16_t" | "int32_t" |
+ "uint32_t" | "int64_t" | "uint64_t" | "uintptr_t" |
+ "intptr_t" | "ptrdiff_t" => true,
+ "size_t" | "ssize_t" => self.options.size_t_is_usize,
+ _ => false,
+ }
+ }
+
/// Get a reference to the set of items we should generate.
pub fn codegen_items(&self) -> &ItemSet {
assert!(self.in_codegen_phase());
@@ -2307,7 +2311,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
// game.
if self.options().allowlisted_types.is_empty() &&
self.options().allowlisted_functions.is_empty() &&
- self.options().allowlisted_vars.is_empty()
+ self.options().allowlisted_vars.is_empty() &&
+ self.options().allowlisted_files.is_empty()
{
return true;
}
@@ -2318,6 +2323,23 @@ If you encounter an error missing from this list, please file an issue or a PR!"
return true;
}
+ // Items with a source location in an explicitly allowlisted file
+ // are always included.
+ if !self.options().allowlisted_files.is_empty() {
+ if let Some(location) = item.location() {
+ let (file, _, _, _) = location.location();
+ if let Some(filename) = file.name() {
+ if self
+ .options()
+ .allowlisted_files
+ .matches(filename)
+ {
+ return true;
+ }
+ }
+ }
+ }
+
let name = item.path_for_allowlisting(self)[1..].join("::");
debug!("allowlisted_items: testing {:?}", name);
match *item.kind() {
@@ -2352,7 +2374,10 @@ If you encounter an error missing from this list, please file an issue or a PR!"
TypeKind::Opaque |
TypeKind::TypeParam => return true,
_ => {}
- };
+ }
+ if self.is_stdint_type(&name) {
+ return true;
+ }
}
// Unnamed top-level enums are special and we
@@ -2382,7 +2407,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
);
let name = prefix_path[1..].join("::");
prefix_path.pop().unwrap();
- self.options().allowlisted_vars.matches(&name)
+ self.options().allowlisted_vars.matches(name)
})
}
}
@@ -2429,16 +2454,24 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.allowlisted = Some(allowlisted);
self.codegen_items = Some(codegen_items);
+ let mut warnings = Vec::new();
+
for item in self.options().allowlisted_functions.unmatched_items() {
- warn!("unused option: --allowlist-function {}", item);
+ warnings
+ .push(format!("unused option: --allowlist-function {}", item));
}
for item in self.options().allowlisted_vars.unmatched_items() {
- warn!("unused option: --allowlist-var {}", item);
+ warnings.push(format!("unused option: --allowlist-var {}", item));
}
for item in self.options().allowlisted_types.unmatched_items() {
- warn!("unused option: --allowlist-type {}", item);
+ warnings.push(format!("unused option: --allowlist-type {}", item));
+ }
+
+ for msg in warnings {
+ warn!("{}", msg);
+ self.warnings.push(msg);
}
}
@@ -2462,6 +2495,70 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.generated_bindgen_complex.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 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");
@@ -2656,37 +2753,52 @@ If you encounter an error missing from this list, please file an issue or a PR!"
/// Check if `--no-partialeq` flag is enabled for this item.
pub fn no_partialeq_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_partialeq_types.matches(&name)
+ self.options().no_partialeq_types.matches(name)
}
/// Check if `--no-copy` flag is enabled for this item.
pub fn no_copy_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_copy_types.matches(&name)
+ self.options().no_copy_types.matches(name)
}
/// Check if `--no-debug` flag is enabled for this item.
pub fn no_debug_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_debug_types.matches(&name)
+ self.options().no_debug_types.matches(name)
}
/// Check if `--no-default` flag is enabled for this item.
pub fn no_default_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_default_types.matches(&name)
+ self.options().no_default_types.matches(name)
}
/// Check if `--no-hash` flag is enabled for this item.
pub fn no_hash_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().no_hash_types.matches(&name)
+ self.options().no_hash_types.matches(name)
}
/// Check if `--must-use-type` flag is enabled for this item.
pub fn must_use_type_by_name(&self, item: &Item) -> bool {
let name = item.path_for_allowlisting(self)[1..].join("::");
- self.options().must_use_types.matches(&name)
+ self.options().must_use_types.matches(name)
+ }
+
+ 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()
+ }
+ }
+
+ 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)
}
}
diff --git a/src/ir/derive.rs b/ir/derive.rs
index 594ce2a..594ce2a 100644
--- a/src/ir/derive.rs
+++ b/ir/derive.rs
diff --git a/src/ir/dot.rs b/ir/dot.rs
index f7d07f1..f7d07f1 100644
--- a/src/ir/dot.rs
+++ b/ir/dot.rs
diff --git a/src/ir/enum_ty.rs b/ir/enum_ty.rs
index 97455c9..63871fd 100644
--- a/src/ir/enum_ty.rs
+++ b/ir/enum_ty.rs
@@ -6,7 +6,7 @@ use super::item::Item;
use super::ty::{Type, TypeKind};
use crate::clang;
use crate::ir::annotations::Annotations;
-use crate::parse::{ClangItemParser, ParseError};
+use crate::parse::ParseError;
use crate::regex_set::RegexSet;
/// An enum representing custom handling that can be given to a variant.
@@ -102,8 +102,8 @@ impl Enum {
let name = cursor.spelling();
let annotations = Annotations::new(&cursor);
let custom_behavior = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
+ .options()
+ .last_callback(|callbacks| {
callbacks
.enum_variant_behavior(type_name, &name, val)
})
@@ -119,8 +119,8 @@ impl Enum {
});
let new_name = ctx
- .parse_callbacks()
- .and_then(|callbacks| {
+ .options()
+ .last_callback(|callbacks| {
callbacks.enum_variant_name(type_name, &name, val)
})
.or_else(|| {
@@ -156,7 +156,7 @@ impl Enum {
let path = item.path_for_allowlisting(ctx);
let enum_ty = item.expect_type();
- if enums.matches(&path[1..].join("::")) {
+ if enums.matches(path[1..].join("::")) {
return true;
}
@@ -165,7 +165,7 @@ impl Enum {
return false;
}
- self.variants().iter().any(|v| enums.matches(&v.name()))
+ self.variants().iter().any(|v| enums.matches(v.name()))
}
/// Returns the final representation of the enum.
@@ -187,10 +187,25 @@ impl Enum {
&ctx.options().bitfield_enums,
item,
) {
- EnumVariation::NewType { is_bitfield: true }
+ 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 }
+ 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,
diff --git a/src/ir/function.rs b/ir/function.rs
index a3a2bbf..baa2c36 100644
--- a/src/ir/function.rs
+++ b/ir/function.rs
@@ -6,20 +6,20 @@ use super::dot::DotAttributes;
use super::item::Item;
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::TypeKind;
-use crate::clang;
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
+use crate::callbacks::{ItemInfo, ItemKind};
+use crate::clang::{self, Attribute};
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
use clang_sys::{self, CXCallingConv};
use proc_macro2;
use quote;
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)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FunctionKind {
/// A plain, free function.
Function,
@@ -131,6 +131,11 @@ impl Function {
self.signature
}
+ /// Get this function's comment.
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_deref()
+ }
+
/// Get this function's kind.
pub fn kind(&self) -> FunctionKind {
self.kind
@@ -165,8 +170,8 @@ impl DotAttributes for Function {
}
}
-/// An ABI extracted from a clang cursor.
-#[derive(Debug, Copy, Clone)]
+/// A valid rust ABI.
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
pub enum Abi {
/// The default C ABI.
C,
@@ -176,35 +181,82 @@ pub enum Abi {
Fastcall,
/// The "thiscall" ABI.
ThisCall,
+ /// The "vectorcall" ABI.
+ Vectorcall,
/// The "aapcs" ABI.
Aapcs,
/// The "win64" ABI.
Win64,
+ /// The "C-unwind" ABI.
+ CUnwind,
+}
+
+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),
+ "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),
+ _ => 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::Fastcall => "fastcall",
+ Self::ThisCall => "thiscall",
+ Self::Vectorcall => "vectorcall",
+ Self::Aapcs => "aapcs",
+ Self::Win64 => "win64",
+ Self::CUnwind => "C-unwind",
+ };
+
+ 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 {
+ Known(Abi),
/// An unknown or invalid ABI.
Unknown(CXCallingConv),
}
-impl Abi {
+impl ClangAbi {
/// Returns whether this Abi is known or not.
fn is_unknown(&self) -> bool {
- matches!(*self, Abi::Unknown(..))
+ matches!(*self, ClangAbi::Unknown(..))
}
}
-impl quote::ToTokens for Abi {
+impl quote::ToTokens for ClangAbi {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
- tokens.append_all(match *self {
- Abi::C => quote! { "C" },
- Abi::Stdcall => quote! { "stdcall" },
- Abi::Fastcall => quote! { "fastcall" },
- Abi::ThisCall => quote! { "thiscall" },
- Abi::Aapcs => quote! { "aapcs" },
- Abi::Win64 => quote! { "win64" },
- Abi::Unknown(cc) => panic!(
+ match *self {
+ Self::Known(abi) => abi.to_tokens(tokens),
+ Self::Unknown(cc) => panic!(
"Cannot turn unknown calling convention to tokens: {:?}",
cc
),
- });
+ }
}
}
@@ -220,25 +272,27 @@ pub struct FunctionSig {
/// Whether this function is variadic.
is_variadic: bool,
+ is_divergent: bool,
/// Whether this function's return value must be used.
must_use: bool,
/// The ABI of this function.
- abi: Abi,
+ abi: ClangAbi,
}
-fn get_abi(cc: CXCallingConv) -> Abi {
+fn get_abi(cc: CXCallingConv) -> ClangAbi {
use clang_sys::*;
match cc {
- CXCallingConv_Default => Abi::C,
- CXCallingConv_C => Abi::C,
- CXCallingConv_X86StdCall => Abi::Stdcall,
- CXCallingConv_X86FastCall => Abi::Fastcall,
- CXCallingConv_X86ThisCall => Abi::ThisCall,
- CXCallingConv_AAPCS => Abi::Aapcs,
- CXCallingConv_X86_64Win64 => Abi::Win64,
- other => Abi::Unknown(other),
+ 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),
+ other => ClangAbi::Unknown(other),
}
}
@@ -344,23 +398,6 @@ fn args_from_ty_and_cursor(
}
impl FunctionSig {
- /// Construct a new function signature.
- pub fn new(
- return_type: TypeId,
- argument_types: Vec<(Option<String>, TypeId)>,
- is_variadic: bool,
- must_use: bool,
- abi: Abi,
- ) -> Self {
- FunctionSig {
- return_type,
- argument_types,
- is_variadic,
- must_use,
- abi,
- }
- }
-
/// Construct a new function signature from the given Clang type.
pub fn from_ty(
ty: &clang::Type,
@@ -438,8 +475,23 @@ impl FunctionSig {
}
};
- let must_use = ctx.options().enable_function_attribute_detection &&
- cursor.has_warn_unused_result_attr();
+ let (must_use, mut is_divergent) =
+ if ctx.options().enable_function_attribute_detection {
+ let [must_use, no_return, no_return_cpp] = cursor.has_attrs(&[
+ Attribute::MUST_USE,
+ Attribute::NO_RETURN,
+ Attribute::NO_RETURN_CPP,
+ ]);
+ (must_use, no_return || no_return_cpp)
+ } else {
+ Default::default()
+ };
+
+ // This looks easy to break but the clang parser keeps the type spelling clean even if
+ // other attributes are added.
+ is_divergent =
+ is_divergent || ty.spelling().contains("__attribute__((noreturn))");
+
let is_method = kind == CXCursor_CXXMethod;
let is_constructor = kind == CXCursor_Constructor;
let is_destructor = kind == CXCursor_Destructor;
@@ -513,13 +565,21 @@ impl FunctionSig {
call_conv = cursor_call_conv;
}
}
+
let abi = get_abi(call_conv);
if abi.is_unknown() {
warn!("Unknown calling convention: {:?}", call_conv);
}
- Ok(Self::new(ret, args, ty.is_variadic(), must_use, abi))
+ Ok(FunctionSig {
+ return_type: ret,
+ argument_types: args,
+ is_variadic: ty.is_variadic(),
+ is_divergent,
+ must_use,
+ abi,
+ })
}
/// Get this function signature's return type.
@@ -533,8 +593,27 @@ impl FunctionSig {
}
/// Get this function signature's ABI.
- pub fn abi(&self) -> Abi {
- self.abi
+ pub(crate) fn abi(
+ &self,
+ ctx: &BindgenContext,
+ name: Option<&str>,
+ ) -> ClangAbi {
+ // FIXME (pvdrz): Try to do this check lazily instead. Maybe store the ABI inside `ctx`
+ // instead?.
+ 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 {
+ self.abi
+ }
}
/// Is this function signature variadic?
@@ -564,7 +643,11 @@ impl FunctionSig {
return false;
}
- matches!(self.abi, Abi::C | Abi::Unknown(..))
+ matches!(self.abi, ClangAbi::Known(Abi::C) | ClangAbi::Unknown(..))
+ }
+
+ pub(crate) fn is_divergent(&self) -> bool {
+ self.is_divergent
}
}
@@ -581,7 +664,6 @@ impl ClangSubItemParser for Function {
};
debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
-
let visibility = cursor.visibility();
if visibility != CXVisibility_Default {
return Err(ParseError::Continue);
@@ -591,15 +673,6 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}
- if cursor.is_inlined_function() {
- if !context.options().generate_inline_functions {
- return Err(ParseError::Continue);
- }
- if cursor.is_deleted_function() {
- return Err(ParseError::Continue);
- }
- }
-
let linkage = cursor.linkage();
let linkage = match linkage {
CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
@@ -607,6 +680,30 @@ impl ClangSubItemParser for Function {
_ => 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)?;
@@ -626,12 +723,22 @@ impl ClangSubItemParser for Function {
// 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 comment = cursor.raw_comment();
let function =
- Self::new(name, mangled_name, sig, comment, kind, linkage);
+ Self::new(name.clone(), mangled_name, sig, comment, kind, linkage);
+
Ok(ParseResult::New(function, Some(cursor)))
}
}
diff --git a/src/ir/int.rs b/ir/int.rs
index 22838e8..22838e8 100644
--- a/src/ir/int.rs
+++ b/ir/int.rs
diff --git a/src/ir/item.rs b/ir/item.rs
index 8692575..40f6f7d 100644
--- a/src/ir/item.rs
+++ b/ir/item.rs
@@ -3,7 +3,6 @@
use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME};
use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult};
use super::annotations::Annotations;
-use super::comment;
use super::comp::{CompKind, MethodKind};
use super::context::{BindgenContext, ItemId, PartialType, TypeId};
use super::derive::{
@@ -19,9 +18,7 @@ use super::template::{AsTemplateParam, TemplateParameters};
use super::traversal::{EdgeKind, Trace, Tracer};
use super::ty::{Type, TypeKind};
use crate::clang;
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
use clang_sys;
use lazycell::LazyCell;
use regex;
@@ -515,9 +512,9 @@ impl Item {
return None;
}
- self.comment.as_ref().map(|comment| {
- comment::preprocess(comment, self.codegen_depth(ctx))
- })
+ self.comment
+ .as_ref()
+ .map(|comment| ctx.options().process_comment(comment))
}
/// What kind of item is this?
@@ -530,6 +527,11 @@ impl Item {
&mut self.kind
}
+ /// Where in the source is this item located?
+ pub fn location(&self) -> Option<&clang::SourceLocation> {
+ self.location.as_ref()
+ }
+
/// Get an identifier that differentiates this item from its siblings.
///
/// This should stay relatively stable in the face of code motion outside or
@@ -645,7 +647,7 @@ impl Item {
if let Some(location) = &self.location {
let (file, _, _, _) = location.location();
if let Some(filename) = file.name() {
- if ctx.options().blocklisted_files.matches(&filename) {
+ if ctx.options().blocklisted_files.matches(filename) {
return true;
}
}
@@ -927,8 +929,8 @@ impl Item {
let name = names.join("_");
let name = if opt.user_mangled == UserMangled::Yes {
- ctx.parse_callbacks()
- .and_then(|callbacks| callbacks.item_name(&name))
+ ctx.options()
+ .last_callback(|callbacks| callbacks.item_name(&name))
.unwrap_or(name)
} else {
name
@@ -1091,6 +1093,11 @@ impl Item {
_ => return None,
})
}
+
+ /// Whether this is a #[must_use] type.
+ pub fn must_use(&self, ctx: &BindgenContext) -> bool {
+ self.annotations().must_use_type() || ctx.must_use_type_by_name(self)
+ }
}
impl<T> IsOpaque for T
@@ -1298,8 +1305,8 @@ fn visit_child(
}
}
-impl ClangItemParser for Item {
- fn builtin_type(
+impl Item {
+ pub(crate) fn builtin_type(
kind: TypeKind,
is_const: bool,
ctx: &mut BindgenContext,
@@ -1324,7 +1331,7 @@ impl ClangItemParser for Item {
id.as_type_id_unchecked()
}
- fn parse(
+ pub(crate) fn parse(
cursor: clang::Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext,
@@ -1470,7 +1477,7 @@ impl ClangItemParser for Item {
}
}
- fn from_ty_or_ref(
+ pub(crate) fn from_ty_or_ref(
ty: clang::Type,
location: clang::Cursor,
parent_id: Option<ItemId>,
@@ -1490,7 +1497,7 @@ impl ClangItemParser for Item {
///
/// Typerefs are resolved once parsing is completely done, see
/// `BindgenContext::resolve_typerefs`.
- fn from_ty_or_ref_with_id(
+ pub(crate) fn from_ty_or_ref_with_id(
potential_id: ItemId,
ty: clang::Type,
location: clang::Cursor,
@@ -1545,7 +1552,7 @@ impl ClangItemParser for Item {
potential_id.as_type_id_unchecked()
}
- fn from_ty(
+ pub(crate) fn from_ty(
ty: &clang::Type,
location: clang::Cursor,
parent_id: Option<ItemId>,
@@ -1563,7 +1570,7 @@ impl ClangItemParser for Item {
/// critical some times to obtain information, an optional parent item id,
/// that will, if it's `None`, become the current module id, and the
/// context.
- fn from_ty_with_id(
+ pub(crate) fn from_ty_with_id(
id: ItemId,
ty: &clang::Type,
location: clang::Cursor,
@@ -1733,7 +1740,7 @@ impl ClangItemParser for Item {
/// A named type is a template parameter, e.g., the "T" in Foo<T>. They're
/// always local so it's the only exception when there's no declaration for
/// a type.
- fn type_param(
+ pub(crate) fn type_param(
with_id: Option<ItemId>,
location: clang::Cursor,
ctx: &mut BindgenContext,
@@ -1889,7 +1896,7 @@ impl ClangItemParser for Item {
// See tests/headers/const_tparam.hpp and
// tests/headers/variadic_tname.hpp.
- let name = ty_spelling.replace("const ", "").replace(".", "");
+ let name = ty_spelling.replace("const ", "").replace('.', "");
let id = with_id.unwrap_or_else(|| ctx.next_item_id());
let item = Item::new(
diff --git a/src/ir/item_kind.rs b/ir/item_kind.rs
index 4a12fef..4a12fef 100644
--- a/src/ir/item_kind.rs
+++ b/ir/item_kind.rs
diff --git a/src/ir/layout.rs b/ir/layout.rs
index 6cf9113..6f45030 100644
--- a/src/ir/layout.rs
+++ b/ir/layout.rs
@@ -7,7 +7,7 @@ use crate::ir::context::BindgenContext;
use std::cmp;
/// A type that represents the struct layout of a type.
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Layout {
/// The size (in bytes) of this layout.
pub size: usize,
@@ -93,7 +93,7 @@ impl Layout {
}
/// When we are treating a type as opaque, it is just a blob with a `Layout`.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Opaque(pub Layout);
impl Opaque {
diff --git a/src/ir/mod.rs b/ir/mod.rs
index 8f6a2da..8f6a2da 100644
--- a/src/ir/mod.rs
+++ b/ir/mod.rs
diff --git a/src/ir/module.rs b/ir/module.rs
index d5aca94..d5aca94 100644
--- a/src/ir/module.rs
+++ b/ir/module.rs
diff --git a/src/ir/objc.rs b/ir/objc.rs
index 0845ad0..4f340f6 100644
--- a/src/ir/objc.rs
+++ b/ir/objc.rs
@@ -6,7 +6,6 @@ use super::item::Item;
use super::traversal::{Trace, Tracer};
use super::ty::TypeKind;
use crate::clang;
-use crate::parse::ClangItemParser;
use clang_sys::CXChildVisit_Continue;
use clang_sys::CXCursor_ObjCCategoryDecl;
use clang_sys::CXCursor_ObjCClassMethodDecl;
@@ -261,7 +260,17 @@ impl ObjCMethod {
if name.is_empty() {
None
} else {
- Some(Ident::new(name, Span::call_site()))
+ // Try to parse the current name as an identifier. This might fail if the
+ // name is a keyword so we try to prepend "r#" 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)
+ })
+ .expect("Invalid identifier"),
+ )
}
})
.collect();
diff --git a/src/ir/template.rs b/ir/template.rs
index 8b06748..e3ef6a9 100644
--- a/src/ir/template.rs
+++ b/ir/template.rs
@@ -31,7 +31,6 @@ use super::context::{BindgenContext, ItemId, TypeId};
use super::item::{IsOpaque, Item, ItemAncestors};
use super::traversal::{EdgeKind, Trace, Tracer};
use crate::clang;
-use crate::parse::ClangItemParser;
/// Template declaration (and such declaration's template parameters) related
/// methods.
diff --git a/src/ir/traversal.rs b/ir/traversal.rs
index 088e744..f14483f 100644
--- a/src/ir/traversal.rs
+++ b/ir/traversal.rs
@@ -179,17 +179,10 @@ pub enum EdgeKind {
/// A predicate to allow visiting only sub-sets of the whole IR graph by
/// excluding certain edges from being followed by the traversal.
-pub trait TraversalPredicate {
- /// Should the traversal follow this edge, and visit everything that is
- /// reachable through it?
- fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool;
-}
-
-impl TraversalPredicate for for<'a> fn(&'a BindgenContext, Edge) -> bool {
- fn should_follow(&self, ctx: &BindgenContext, edge: Edge) -> bool {
- (*self)(ctx, edge)
- }
-}
+///
+/// The predicate must return true if the traversal should follow this edge
+/// and visit everything that is reachable through it.
+pub type TraversalPredicate = for<'a> fn(&'a BindgenContext, Edge) -> bool;
/// A `TraversalPredicate` implementation that follows all edges, and therefore
/// traversals using this predicate will see the whole IR graph reachable from
@@ -378,11 +371,10 @@ pub trait Trace {
/// An graph traversal of the transitive closure of references between items.
///
/// See `BindgenContext::allowlisted_items` for more information.
-pub struct ItemTraversal<'ctx, Storage, Queue, Predicate>
+pub struct ItemTraversal<'ctx, Storage, Queue>
where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
- Predicate: TraversalPredicate,
{
ctx: &'ctx BindgenContext,
@@ -393,25 +385,23 @@ where
queue: Queue,
/// The predicate that determines which edges this traversal will follow.
- predicate: Predicate,
+ predicate: TraversalPredicate,
/// The item we are currently traversing.
currently_traversing: Option<ItemId>,
}
-impl<'ctx, Storage, Queue, Predicate>
- ItemTraversal<'ctx, Storage, Queue, Predicate>
+impl<'ctx, Storage, Queue> ItemTraversal<'ctx, Storage, Queue>
where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
- Predicate: TraversalPredicate,
{
/// Begin a new traversal, starting from the given roots.
pub fn new<R>(
ctx: &'ctx BindgenContext,
roots: R,
- predicate: Predicate,
- ) -> ItemTraversal<'ctx, Storage, Queue, Predicate>
+ predicate: TraversalPredicate,
+ ) -> ItemTraversal<'ctx, Storage, Queue>
where
R: IntoIterator<Item = ItemId>,
{
@@ -433,16 +423,14 @@ where
}
}
-impl<'ctx, Storage, Queue, Predicate> Tracer
- for ItemTraversal<'ctx, Storage, Queue, Predicate>
+impl<'ctx, Storage, Queue> Tracer for ItemTraversal<'ctx, Storage, Queue>
where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
- Predicate: TraversalPredicate,
{
fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) {
let edge = Edge::new(item, kind);
- if !self.predicate.should_follow(self.ctx, edge) {
+ if !(self.predicate)(self.ctx, edge) {
return;
}
@@ -454,12 +442,10 @@ where
}
}
-impl<'ctx, Storage, Queue, Predicate> Iterator
- for ItemTraversal<'ctx, Storage, Queue, Predicate>
+impl<'ctx, Storage, Queue> Iterator for ItemTraversal<'ctx, Storage, Queue>
where
Storage: TraversalStorage<'ctx>,
Queue: TraversalQueue,
- Predicate: TraversalPredicate,
{
type Item = ItemId;
@@ -488,21 +474,5 @@ where
///
/// See `BindgenContext::assert_no_dangling_item_traversal` for more
/// information.
-pub type AssertNoDanglingItemsTraversal<'ctx> = ItemTraversal<
- 'ctx,
- Paths<'ctx>,
- VecDeque<ItemId>,
- for<'a> fn(&'a BindgenContext, Edge) -> bool,
->;
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- #[allow(dead_code)]
- fn traversal_predicate_is_object_safe() {
- // This should compile only if TraversalPredicate is object safe.
- fn takes_by_trait_object(_: &dyn TraversalPredicate) {}
- }
-}
+pub type AssertNoDanglingItemsTraversal<'ctx> =
+ ItemTraversal<'ctx, Paths<'ctx>, VecDeque<ItemId>>;
diff --git a/src/ir/ty.rs b/ir/ty.rs
index d573408..fef340d 100644
--- a/src/ir/ty.rs
+++ b/ir/ty.rs
@@ -14,7 +14,7 @@ use super::template::{
};
use super::traversal::{EdgeKind, Trace, Tracer};
use crate::clang::{self, Cursor};
-use crate::parse::{ClangItemParser, ParseError, ParseResult};
+use crate::parse::{ParseError, ParseResult};
use std::borrow::Cow;
use std::io;
@@ -95,6 +95,11 @@ impl Type {
matches!(self.kind, TypeKind::BlockPointer(..))
}
+ /// Is this an integer type, including `bool` or `char`?
+ pub fn is_int(&self) -> bool {
+ matches!(self.kind, TypeKind::Int(_))
+ }
+
/// Is this a compound type?
pub fn is_comp(&self) -> bool {
matches!(self.kind, TypeKind::Comp(..))
@@ -564,7 +569,7 @@ impl TemplateParameters for TypeKind {
}
/// The kind of float this type represents.
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FloatKind {
/// A `float`.
Float,
@@ -698,7 +703,12 @@ impl Type {
let layout = ty.fallible_layout(ctx).ok();
let cursor = ty.declaration();
- let mut name = cursor.spelling();
+ 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: {:?}",
@@ -732,7 +742,7 @@ impl Type {
if is_canonical_objcpointer && is_template_type_param {
// Objective-C generics are just ids with fancy name.
// To keep it simple, just name them ids
- name = "id".to_owned();
+ name = Some("id".to_owned());
}
}
@@ -861,7 +871,7 @@ impl Type {
return Err(ParseError::Recurse);
}
} else {
- name = location.spelling();
+ name = Some(location.spelling());
}
let complex = CompInfo::from_ty(
@@ -903,7 +913,7 @@ impl Type {
CXType_Typedef
);
- name = current.spelling();
+ name = Some(location.spelling());
let inner_ty = cur
.typedef_type()
@@ -1031,7 +1041,16 @@ impl Type {
CXType_ObjCObjectPointer |
CXType_MemberPointer |
CXType_Pointer => {
- let pointee = ty.pointee_type().unwrap();
+ 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)
@@ -1080,9 +1099,9 @@ impl Type {
}
CXType_Typedef => {
let inner = cursor.typedef_type().expect("Not valid Type?");
- let inner =
+ let inner_id =
Item::from_ty_or_ref(inner, location, None, ctx);
- if inner == potential_id {
+ if inner_id == potential_id {
warn!(
"Generating oqaque type instead of self-referential \
typedef");
@@ -1090,16 +1109,31 @@ impl Type {
// within the clang parsing.
TypeKind::Opaque
} else {
- TypeKind::Alias(inner)
+ // 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 name.is_empty() {
+ if !is_anonymous {
let pretty_name = ty.spelling();
if clang::is_valid_identifier(&pretty_name) {
- name = pretty_name;
+ name = Some(pretty_name);
}
}
@@ -1114,12 +1148,12 @@ impl Type {
)
.expect("Not a complex type?");
- if name.is_empty() {
+ 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 = pretty_name;
+ name = Some(pretty_name);
}
}
@@ -1131,8 +1165,7 @@ impl Type {
location,
None,
ctx,
- )
- .expect("Not able to resolve vector element?");
+ )?;
TypeKind::Vector(inner, ty.num_elements().unwrap())
}
CXType_ConstantArray => {
@@ -1159,7 +1192,9 @@ impl Type {
CXType_ObjCClass | CXType_ObjCInterface => {
let interface = ObjCInterface::from_ty(&location, ctx)
.expect("Not a valid objc interface?");
- name = interface.rust_name();
+ if !is_anonymous {
+ name = Some(interface.rust_name());
+ }
TypeKind::ObjCInterface(interface)
}
CXType_Dependent => {
@@ -1177,7 +1212,7 @@ impl Type {
}
};
- let name = if name.is_empty() { None } else { Some(name) };
+ name = name.filter(|n| !n.is_empty());
let is_const = ty.is_const() ||
(ty.kind() == CXType_ConstantArray &&
@@ -1197,6 +1232,13 @@ impl Trace for Type {
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) |
diff --git a/src/ir/var.rs b/ir/var.rs
index cd17937..903e1ff 100644
--- a/src/ir/var.rs
+++ b/ir/var.rs
@@ -7,12 +7,10 @@ use super::function::cursor_mangling;
use super::int::IntKind;
use super::item::Item;
use super::ty::{FloatKind, TypeKind};
-use crate::callbacks::MacroParsingBehavior;
+use crate::callbacks::{ItemInfo, ItemKind, MacroParsingBehavior};
use crate::clang;
use crate::clang::ClangToken;
-use crate::parse::{
- ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
-};
+use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
use cexpr;
use std::io;
use std::num::Wrapping;
@@ -149,52 +147,27 @@ fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind {
}
}
-/// Determines whether a set of tokens from a CXCursor_MacroDefinition
-/// represent a function-like macro. If so, calls the func_macro callback
-/// and returns `Err(ParseError::Continue)` to signal to skip further
-/// processing. If conversion to UTF-8 fails (it is performed only where it
-/// should be infallible), then `Err(ParseError::Continue)` is returned as well.
+/// 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,
- tokens: &[ClangToken],
callbacks: &dyn crate::callbacks::ParseCallbacks,
-) -> Result<(), ParseError> {
- // TODO: Hoist the `is_macro_function_like` check into this function's
- // caller, and thus avoid allocating the `tokens` vector for non-functional
- // macros.
- let is_functional_macro = cursor.is_macro_function_like();
-
- if !is_functional_macro {
- return Ok(());
- }
-
+) {
let is_closing_paren = |t: &ClangToken| {
// Test cheap token kind before comparing exact spellings.
t.kind == clang_sys::CXToken_Punctuation && t.spelling() == b")"
};
- let boundary = tokens.iter().position(is_closing_paren);
-
- let mut spelled = tokens.iter().map(ClangToken::spelling);
- // Add 1, to convert index to length.
- let left = spelled
- .by_ref()
- .take(boundary.ok_or(ParseError::Continue)? + 1);
- let left = left.collect::<Vec<_>>().concat();
- let left = String::from_utf8(left).map_err(|_| ParseError::Continue)?;
- let right = spelled;
- // Drop last token with LLVM < 4.0, due to an LLVM bug.
- //
- // See:
- // https://bugs.llvm.org//show_bug.cgi?id=9069
- let len = match (right.len(), crate::clang_version().parsed) {
- (len, Some((v, _))) if len > 0 && v < 4 => len - 1,
- (len, _) => len,
- };
- let right: Vec<_> = right.take(len).collect();
- callbacks.func_macro(&left, &right);
-
- // We handled the macro, skip future macro processing.
- Err(ParseError::Continue)
+ 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 {
@@ -207,9 +180,7 @@ impl ClangSubItemParser for Var {
use clang_sys::*;
match cursor.kind() {
CXCursor_MacroDefinition => {
- let tokens: Vec<_> = cursor.tokens().iter().collect();
-
- if let Some(callbacks) = ctx.parse_callbacks() {
+ for callbacks in &ctx.options().parse_callbacks {
match callbacks.will_parse_macro(&cursor.spelling()) {
MacroParsingBehavior::Ignore => {
return Err(ParseError::Continue);
@@ -217,10 +188,14 @@ impl ClangSubItemParser for Var {
MacroParsingBehavior::Default => {}
}
- handle_function_macro(&cursor, &tokens, callbacks)?;
+ 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, &tokens);
+ let value = parse_macro(ctx, &cursor);
let (id, value) = match value {
Some(v) => v,
@@ -272,15 +247,15 @@ impl ClangSubItemParser for Var {
true,
ctx,
);
- if let Some(callbacks) = ctx.parse_callbacks() {
+ 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
- .parse_callbacks()
- .and_then(|c| c.int_macro(&name, value))
+ .options()
+ .last_callback(|c| c.int_macro(&name, value))
.unwrap_or_else(|| {
default_macro_constant_type(ctx, value)
});
@@ -297,7 +272,20 @@ impl ClangSubItemParser for Var {
))
}
CXCursor_VarDecl => {
- let name = cursor.spelling();
+ 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);
@@ -308,18 +296,19 @@ impl ClangSubItemParser for Var {
// TODO(emilio): do we have to special-case constant arrays in
// some other places?
let is_const = ty.is_const() ||
- (ty.kind() == CXType_ConstantArray &&
+ ([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_eq!(
- ty.kind(),
- CXType_Auto,
+ assert!(
+ matches!(ty.kind(), CXType_Auto | CXType_Unexposed),
"Couldn't resolve constant type, and it \
- wasn't an nondeductible auto type!"
+ wasn't an nondeductible auto type or unexposed \
+ type!"
);
return Err(e);
}
@@ -348,8 +337,7 @@ impl ClangSubItemParser for Var {
let mut val = cursor.evaluate().and_then(|v| v.as_int());
if val.is_none() || !kind.signedness_matches(val.unwrap()) {
- let tu = ctx.translation_unit();
- val = get_integer_literal_from_cursor(&cursor, tu);
+ val = get_integer_literal_from_cursor(&cursor);
}
val.map(|val| {
@@ -387,29 +375,14 @@ impl ClangSubItemParser for Var {
/// Try and parse a macro using all the macros parsed until now.
fn parse_macro(
ctx: &BindgenContext,
- tokens: &[ClangToken],
+ cursor: &clang::Cursor,
) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
use cexpr::expr;
- let mut cexpr_tokens: Vec<_> = tokens
- .iter()
- .filter_map(ClangToken::as_cexpr_token)
- .collect();
+ let cexpr_tokens = cursor.cexpr_tokens();
let parser = expr::IdentifierParser::new(ctx.parsed_macros());
- if let Ok((_, (id, val))) = parser.macro_definition(&cexpr_tokens) {
- return Some((id.into(), val));
- }
-
- // Try without the last token, to workaround a libclang bug in versions
- // previous to 4.0.
- //
- // See:
- // https://bugs.llvm.org//show_bug.cgi?id=9069
- // https://reviews.llvm.org/D26446
- cexpr_tokens.pop()?;
-
match parser.macro_definition(&cexpr_tokens) {
Ok((_, (id, val))) => Some((id.into(), val)),
_ => None,
@@ -429,10 +402,7 @@ fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
}
}
-fn get_integer_literal_from_cursor(
- cursor: &clang::Cursor,
- unit: &clang::TranslationUnit,
-) -> Option<i64> {
+fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64> {
use clang_sys::*;
let mut value = None;
cursor.visit(|c| {
@@ -441,7 +411,7 @@ fn get_integer_literal_from_cursor(
value = parse_int_literal_tokens(&c);
}
CXCursor_UnexposedExpr => {
- value = get_integer_literal_from_cursor(&c, unit);
+ value = get_integer_literal_from_cursor(&c);
}
_ => (),
}
diff --git a/src/lib.rs b/lib.rs
index 9a90dac..1af6f26 100644
--- a/src/lib.rs
+++ b/lib.rs
@@ -49,11 +49,23 @@ macro_rules! doc_mod {
};
}
+macro_rules! fn_with_regex_arg {
+ ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => {
+ $(#[$attrs])*
+ /// Check the [regular expression arguments] section and the [regex] crate
+ /// documentation for further information.
+ ///
+ /// [regular expression arguments]: ./struct.Builder.html#regular-expression-arguments
+ /// [regex]: <https://docs.rs/regex>
+ pub fn $($tokens)*
+ };
+}
+
mod clang;
mod codegen;
mod deps;
mod features;
-mod ir;
+pub mod ir;
mod parse;
mod regex_set;
mod time;
@@ -66,22 +78,29 @@ doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);
-pub use crate::codegen::{AliasVariation, EnumVariation, MacroTypeVariation};
+use codegen::CodegenError;
+use ir::comment;
+
+pub use crate::codegen::{
+ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
+};
use crate::features::RustFeatures;
pub use crate::features::{
RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS,
};
use crate::ir::context::{BindgenContext, ItemId};
+pub use crate::ir::function::Abi;
use crate::ir::item::Item;
-use crate::parse::{ClangItemParser, ParseError};
-use crate::regex_set::RegexSet;
+use crate::parse::ParseError;
+pub use crate::regex_set::RegexSet;
use std::borrow::Cow;
+use std::env;
use std::fs::{File, OpenOptions};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
-use std::{env, iter};
+use std::rc::Rc;
// Some convenient typedefs for a fast hash map and hash set.
type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>;
@@ -90,6 +109,7 @@ pub(crate) use std::collections::hash_map::Entry;
/// 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") ||
@@ -219,12 +239,20 @@ impl Default for CodegenConfig {
/// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to
/// add additional arguments. For example, to build against a different sysroot a user could set
/// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`.
-#[derive(Debug, Default)]
+///
+/// # Regular expression arguments
+///
+/// Some [`Builder`] methods like the `allowlist_*` and `blocklist_*` family of methods allow
+/// regular expressions as arguments. These regular expressions will be parenthesized and wrapped
+/// in `^` and `$`. So if `<regex>` is passed as argument, the regular expression to be stored will
+/// be `^(<regex>)$`.
+///
+/// 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 `.*`
+/// pattern must be used instead.
+#[derive(Debug, Default, Clone)]
pub struct Builder {
options: BindgenOptions,
- input_headers: Vec<String>,
- // Tuples of unsaved file contents of the form (name, contents).
- input_header_contents: Vec<(String, String)>,
}
/// Construct a new [`Builder`](./struct.Builder.html).
@@ -232,12 +260,26 @@ pub fn builder() -> Builder {
Default::default()
}
+fn get_extra_clang_args() -> Vec<String> {
+ // Add any extra arguments from the environment to the clang command line.
+ let extra_clang_args =
+ match get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS") {
+ None => return vec![],
+ Some(s) => s,
+ };
+ // Try to parse it with shell quoting. If we fail, make it one single big argument.
+ if let Some(strings) = shlex::split(&extra_clang_args) {
+ return strings;
+ }
+ vec![extra_clang_args]
+}
+
impl Builder {
/// Generates the command line flags use for creating `Builder`.
pub fn command_line_flags(&self) -> Vec<String> {
let mut output_vector: Vec<String> = Vec::new();
- if let Some(header) = self.input_headers.last().cloned() {
+ if let Some(header) = self.options.input_headers.last().cloned() {
// Positional argument 'header'
output_vector.push(header);
}
@@ -264,11 +306,19 @@ impl Builder {
codegen::EnumVariation::Rust {
non_exhaustive: true,
} => "rust_non_exhaustive",
- codegen::EnumVariation::NewType { is_bitfield: true } => {
- "bitfield"
- }
- codegen::EnumVariation::NewType { is_bitfield: false } => {
- "newtype"
+ codegen::EnumVariation::NewType {
+ is_bitfield: true,
+ ..
+ } => "bitfield",
+ codegen::EnumVariation::NewType {
+ is_bitfield: false,
+ is_global,
+ } => {
+ if is_global {
+ "newtype_global"
+ } else {
+ "newtype"
+ }
}
codegen::EnumVariation::Consts => "consts",
codegen::EnumVariation::ModuleConsts => "moduleconsts",
@@ -289,9 +339,17 @@ impl Builder {
.push(self.options.default_alias_style.as_str().into());
}
+ if self.options.default_non_copy_union_style != Default::default() {
+ output_vector.push("--default-non-copy-union-style".into());
+ output_vector.push(
+ self.options.default_non_copy_union_style.as_str().into(),
+ );
+ }
+
let regex_sets = &[
(&self.options.bitfield_enums, "--bitfield-enum"),
(&self.options.newtype_enums, "--newtype-enum"),
+ (&self.options.newtype_global_enums, "--newtype-global-enum"),
(&self.options.rustified_enums, "--rustified-enum"),
(
&self.options.rustified_non_exhaustive_enums,
@@ -305,6 +363,11 @@ impl Builder {
(&self.options.type_alias, "--type-alias"),
(&self.options.new_type_alias, "--new-type-alias"),
(&self.options.new_type_alias_deref, "--new-type-alias-deref"),
+ (
+ &self.options.bindgen_wrapper_union,
+ "--bindgen-wrapper-union",
+ ),
+ (&self.options.manually_drop_union, "--manually-drop-union"),
(&self.options.blocklisted_types, "--blocklist-type"),
(&self.options.blocklisted_functions, "--blocklist-function"),
(&self.options.blocklisted_items, "--blocklist-item"),
@@ -313,6 +376,7 @@ impl Builder {
(&self.options.allowlisted_functions, "--allowlist-function"),
(&self.options.allowlisted_types, "--allowlist-type"),
(&self.options.allowlisted_vars, "--allowlist-var"),
+ (&self.options.allowlisted_files, "--allowlist-file"),
(&self.options.no_partialeq_types, "--no-partialeq"),
(&self.options.no_copy_types, "--no-copy"),
(&self.options.no_debug_types, "--no-debug"),
@@ -328,6 +392,13 @@ impl Builder {
}
}
+ for (abi, set) in &self.options.abi_overrides {
+ for item in set.get_items() {
+ output_vector.push("--override-abi".to_owned());
+ output_vector.push(format!("{}={}", item, abi));
+ }
+ }
+
if !self.options.layout_tests {
output_vector.push("--no-layout-tests".into());
}
@@ -525,8 +596,8 @@ impl Builder {
output_vector.push("--no-record-matches".into());
}
- if self.options.size_t_is_usize {
- output_vector.push("--size_t-is-usize".into());
+ if !self.options.size_t_is_usize {
+ output_vector.push("--no-size_t-is-usize".into());
}
if !self.options.rustfmt_bindings {
@@ -568,6 +639,44 @@ impl Builder {
output_vector.push("--explicit-padding".into());
}
+ if self.options.vtable_generation {
+ output_vector.push("--vtable-generation".into());
+ }
+
+ if self.options.sort_semantically {
+ output_vector.push("--sort-semantically".into());
+ }
+
+ if self.options.merge_extern_blocks {
+ output_vector.push("--merge-extern-blocks".into());
+ }
+
+ if self.options.wrap_unsafe_ops {
+ output_vector.push("--wrap-unsafe-ops".into());
+ }
+
+ #[cfg(feature = "cli")]
+ for callbacks in &self.options.parse_callbacks {
+ output_vector.extend(callbacks.cli_args());
+ }
+ if self.options.wrap_static_fns {
+ output_vector.push("--wrap-static-fns".into())
+ }
+
+ if let Some(ref path) = self.options.wrap_static_fns_path {
+ output_vector.push("--wrap-static-fns-path".into());
+ output_vector.push(path.display().to_string());
+ }
+
+ if let Some(ref suffix) = self.options.wrap_static_fns_suffix {
+ output_vector.push("--wrap-static-fns-suffix".into());
+ output_vector.push(suffix.clone());
+ }
+
+ if cfg!(feature = "experimental") {
+ output_vector.push("--experimental".into());
+ }
+
// Add clang arguments
output_vector.push("--".into());
@@ -576,13 +685,13 @@ impl Builder {
output_vector.extend(self.options.clang_args.iter().cloned());
}
- if self.input_headers.len() > 1 {
- // To pass more than one header, we need to pass all but the last
- // header via the `-include` clang arg
- for header in &self.input_headers[..self.input_headers.len() - 1] {
- output_vector.push("-include".to_string());
- output_vector.push(header.clone());
- }
+ // To pass more than one header, we need to pass all but the last
+ // header via the `-include` clang arg
+ for header in &self.options.input_headers
+ [..self.options.input_headers.len().saturating_sub(1)]
+ {
+ output_vector.push("-include".to_string());
+ output_vector.push(header.clone());
}
output_vector
@@ -611,7 +720,7 @@ impl Builder {
/// .unwrap();
/// ```
pub fn header<T: Into<String>>(mut self, header: T) -> Builder {
- self.input_headers.push(header.into());
+ self.options.input_headers.push(header.into());
self
}
@@ -640,7 +749,8 @@ impl Builder {
.to_str()
.expect("Cannot convert current directory name to string")
.to_owned();
- self.input_header_contents
+ self.options
+ .input_header_contents
.push((absolute_path, contents.into()));
self
}
@@ -649,6 +759,13 @@ impl Builder {
///
/// The default is the latest stable Rust version
pub fn rust_target(mut self, rust_target: RustTarget) -> Self {
+ #[allow(deprecated)]
+ if rust_target <= RustTarget::Stable_1_30 {
+ warn!(
+ "The {} rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues",
+ String::from(rust_target)
+ );
+ }
self.options.set_rust_target(rust_target);
self
}
@@ -720,12 +837,6 @@ impl Builder {
self
}
- /// Deprecated alias for allowlist_recursively.
- #[deprecated(note = "Use allowlist_recursively instead")]
- pub fn whitelist_recursively(self, doit: bool) -> Self {
- self.allowlist_recursively(doit)
- }
-
/// Generate `#[macro_use] extern crate objc;` instead of `use objc;`
/// in the prologue of the files generated from objective-c files
pub fn objc_extern_crate(mut self, doit: bool) -> Self {
@@ -758,168 +869,110 @@ impl Builder {
self
}
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "Use blocklist_type instead")]
- pub fn hide_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_type(arg)
- }
-
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "Use blocklist_type instead")]
- pub fn blacklist_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_type(arg)
- }
-
- /// Hide the given type from the generated bindings. Regular expressions are
- /// supported.
- ///
- /// To blocklist types prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_types.insert(arg);
- self
- }
-
- /// Hide the given function from the generated bindings. Regular expressions
- /// are supported.
- #[deprecated(note = "Use blocklist_function instead")]
- pub fn blacklist_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.blocklist_function(arg)
- }
-
- /// Hide the given function from the generated bindings. Regular expressions
- /// are supported.
- ///
- /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_functions.insert(arg);
- self
- }
-
- /// Hide the given item from the generated bindings, regardless of
- /// whether it's a type, function, module, etc. Regular
- /// expressions are supported.
- #[deprecated(note = "Use blocklist_item instead")]
- pub fn blacklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_items.insert(arg);
- self
- }
-
- /// Hide the given item from the generated bindings, regardless of
- /// whether it's a type, function, module, etc. Regular
- /// expressions are supported.
- ///
- /// To blocklist items prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_items.insert(arg);
- self
- }
-
- /// Hide any contents of the given file from the generated bindings,
- /// regardless of whether it's a type, function, module etc.
- pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.blocklisted_files.insert(arg);
- self
- }
-
- /// Treat the given type as opaque in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.opaque_types.insert(arg);
- self
- }
-
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "use allowlist_type instead")]
- pub fn whitelisted_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_type(arg)
+ fn_with_regex_arg! {
+ /// Hide the given type from the generated bindings. Regular expressions are
+ /// supported.
+ ///
+ /// To blocklist types prefixed with "mylib" use `"mylib_.*"`.
+ pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_types.insert(arg);
+ self
+ }
}
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- #[deprecated(note = "use allowlist_type instead")]
- pub fn whitelist_type<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_type(arg)
+ fn_with_regex_arg! {
+ /// Hide the given function from the generated bindings. Regular expressions
+ /// are supported.
+ ///
+ /// Methods can be blocklisted by prefixing the name of the type implementing
+ /// them followed by an underscore. So if `Foo` has a method `bar`, it can
+ /// be blocklisted as `Foo_bar`.
+ ///
+ /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`.
+ pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_functions.insert(arg);
+ self
+ }
}
- /// Allowlist the given type so that it (and all types that it transitively
- /// refers to) appears in the generated bindings. Regular expressions are
- /// supported.
- ///
- /// To allowlist types prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_types.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Hide the given item from the generated bindings, regardless of
+ /// whether it's a type, function, module, etc. Regular
+ /// expressions are supported.
+ ///
+ /// To blocklist items prefixed with "mylib" use `"mylib_.*"`.
+ pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_items.insert(arg);
+ self
+ }
}
- /// Allowlist the given function so that it (and all types that it
- /// transitively refers to) appears in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_functions.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Hide any contents of the given file from the generated bindings,
+ /// regardless of whether it's a type, function, module etc.
+ pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.blocklisted_files.insert(arg);
+ self
+ }
}
- /// Allowlist the given function.
- ///
- /// Deprecated: use allowlist_function instead.
- #[deprecated(note = "use allowlist_function instead")]
- pub fn whitelist_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_function(arg)
+ fn_with_regex_arg! {
+ /// Treat the given type as opaque in the generated bindings. Regular
+ /// expressions are supported.
+ ///
+ /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`.
+ pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.opaque_types.insert(arg);
+ self
+ }
}
- /// Allowlist the given function.
- ///
- /// Deprecated: use allowlist_function instead.
- #[deprecated(note = "use allowlist_function instead")]
- pub fn whitelisted_function<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_function(arg)
+ fn_with_regex_arg! {
+ /// Allowlist the given type so that it (and all types that it transitively
+ /// refers to) appears in the generated bindings. Regular expressions are
+ /// supported.
+ ///
+ /// To allowlist types prefixed with "mylib" use `"mylib_.*"`.
+ pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_types.insert(arg);
+ self
+ }
}
- /// Allowlist the given variable so that it (and all types that it
- /// transitively refers to) appears in the generated bindings. Regular
- /// expressions are supported.
- ///
- /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`.
- /// For more complicated expressions check
- /// [regex](https://docs.rs/regex/*/regex/) docs
- pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.allowlisted_vars.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Allowlist the given function so that it (and all types that it
+ /// transitively refers to) appears in the generated bindings. Regular
+ /// expressions are supported.
+ ///
+ /// Methods can be allowlisted by prefixing the name of the type
+ /// implementing them followed by an underscore. So if `Foo` has a method
+ /// `bar`, it can be allowlisted as `Foo_bar`.
+ ///
+ /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`.
+ pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_functions.insert(arg);
+ self
+ }
}
- /// Deprecated: use allowlist_var instead.
- #[deprecated(note = "use allowlist_var instead")]
- pub fn whitelist_var<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_var(arg)
+ fn_with_regex_arg! {
+ /// Allowlist the given variable so that it (and all types that it
+ /// transitively refers to) appears in the generated bindings. Regular
+ /// expressions are supported.
+ ///
+ /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`.
+ pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_vars.insert(arg);
+ self
+ }
}
- /// Allowlist the given variable.
- ///
- /// Deprecated: use allowlist_var instead.
- #[deprecated(note = "use allowlist_var instead")]
- pub fn whitelisted_var<T: AsRef<str>>(self, arg: T) -> Builder {
- self.allowlist_var(arg)
+ fn_with_regex_arg! {
+ /// Allowlist the given file so that its contents appear in the generated bindings.
+ pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.allowlisted_files.insert(arg);
+ self
+ }
}
/// Set the default style of code to generate for enums
@@ -931,75 +984,101 @@ impl Builder {
self
}
- /// Mark the given enum (or set of enums, if using a pattern) as being
- /// bitfield-like. Regular expressions are supported.
- ///
- /// This makes bindgen generate a type that isn't a rust `enum`. Regular
- /// expressions are supported.
- ///
- /// This is similar to the newtype enum style, but with the bitwise
- /// operators implemented.
- pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.bitfield_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a newtype.
- /// Regular expressions are supported.
- ///
- /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
- /// expressions are supported.
- pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.newtype_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a Rust
- /// enum.
- ///
- /// This makes bindgen generate enums instead of constants. Regular
- /// expressions are supported.
- ///
- /// **Use this with caution**, creating this in unsafe code
- /// (including FFI) with an invalid value will invoke undefined behaviour.
- /// You may want to use the newtype enum style instead.
- pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.rustified_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a Rust
- /// enum with the `#[non_exhaustive]` attribute.
- ///
- /// This makes bindgen generate enums instead of constants. Regular
- /// expressions are supported.
- ///
- /// **Use this with caution**, creating this in unsafe code
- /// (including FFI) with an invalid value will invoke undefined behaviour.
- /// You may want to use the newtype enum style instead.
- pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(
- mut self,
- arg: T,
- ) -> Builder {
- self.options.rustified_non_exhaustive_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a set of
- /// constants that are not to be put into a module.
- pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.constified_enums.insert(arg);
- self
- }
-
- /// Mark the given enum (or set of enums, if using a pattern) as a set of
- /// constants that should be put into a module.
- ///
- /// This makes bindgen generate modules containing constants instead of
- /// just constants. Regular expressions are supported.
- pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.constified_enum_modules.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as being
+ /// bitfield-like. Regular expressions are supported.
+ ///
+ /// This makes bindgen generate a type that isn't a rust `enum`. Regular
+ /// expressions are supported.
+ ///
+ /// This is similar to the newtype enum style, but with the bitwise
+ /// operators implemented.
+ pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.bitfield_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a newtype.
+ /// Regular expressions are supported.
+ ///
+ /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
+ /// expressions are supported.
+ pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.newtype_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a newtype
+ /// whose variants are exposed as global constants.
+ ///
+ /// Regular expressions are supported.
+ ///
+ /// This makes bindgen generate a type that isn't a Rust `enum`. Regular
+ /// expressions are supported.
+ pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.newtype_global_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a Rust
+ /// enum.
+ ///
+ /// This makes bindgen generate enums instead of constants. Regular
+ /// expressions are supported.
+ ///
+ /// **Use this with caution**, creating this in unsafe code
+ /// (including FFI) with an invalid value will invoke undefined behaviour.
+ /// You may want to use the newtype enum style instead.
+ pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.rustified_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a Rust
+ /// enum with the `#[non_exhaustive]` attribute.
+ ///
+ /// This makes bindgen generate enums instead of constants. Regular
+ /// expressions are supported.
+ ///
+ /// **Use this with caution**, creating this in unsafe code
+ /// (including FFI) with an invalid value will invoke undefined behaviour.
+ /// You may want to use the newtype enum style instead.
+ pub fn rustified_non_exhaustive_enum<T: AsRef<str>>(
+ mut self,
+ arg: T,
+ ) -> Builder {
+ self.options.rustified_non_exhaustive_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a set of
+ /// constants that are not to be put into a module.
+ pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.constified_enums.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given enum (or set of enums, if using a pattern) as a set of
+ /// constants that should be put into a module.
+ ///
+ /// This makes bindgen generate modules containing constants instead of
+ /// just constants. Regular expressions are supported.
+ pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.constified_enum_modules.insert(arg);
+ self
+ }
}
/// Set the default type for macro constants
@@ -1020,43 +1099,81 @@ impl Builder {
self
}
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// use regular Rust type aliasing.
- ///
- /// This is the default behavior and should be used if `default_alias_style`
- /// was set to NewType or NewTypeDeref and you want to override it for a
- /// set of typedefs.
- pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.type_alias.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// use regular Rust type aliasing.
+ ///
+ /// This is the default behavior and should be used if `default_alias_style`
+ /// was set to NewType or NewTypeDeref and you want to override it for a
+ /// set of typedefs.
+ pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.type_alias.insert(arg);
+ self
+ }
}
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// be generated as a new type by having the aliased type be wrapped in a
- /// #[repr(transparent)] struct.
- ///
- /// Used to enforce stricter type checking.
- pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.new_type_alias.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// be generated as a new type by having the aliased type be wrapped in a
+ /// #[repr(transparent)] struct.
+ ///
+ /// Used to enforce stricter type checking.
+ pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias.insert(arg);
+ self
+ }
}
- /// Mark the given typedef alias (or set of aliases, if using a pattern) to
- /// be generated as a new type by having the aliased type be wrapped in a
- /// #[repr(transparent)] struct and also have an automatically generated
- /// impl's of `Deref` and `DerefMut` to their aliased type.
- pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
- self.options.new_type_alias_deref.insert(arg);
- self
+ fn_with_regex_arg! {
+ /// Mark the given typedef alias (or set of aliases, if using a pattern) to
+ /// be generated as a new type by having the aliased type be wrapped in a
+ /// #[repr(transparent)] struct and also have an automatically generated
+ /// impl's of `Deref` and `DerefMut` to their aliased type.
+ pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder {
+ self.options.new_type_alias_deref.insert(arg);
+ self
+ }
}
- /// Add a string to prepend to the generated bindings. The string is passed
- /// through without any modification.
- pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.raw_lines.push(arg.into());
+ /// Set the default style of code to generate for unions with a non-Copy member.
+ pub fn default_non_copy_union_style(
+ mut self,
+ arg: codegen::NonCopyUnionStyle,
+ ) -> Self {
+ self.options.default_non_copy_union_style = arg;
self
}
+ fn_with_regex_arg! {
+ /// Mark the given union (or set of union, if using a pattern) to use
+ /// a bindgen-generated wrapper for its members if at least one is non-Copy.
+ pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.bindgen_wrapper_union.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Mark the given union (or set of union, if using a pattern) to use
+ /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy.
+ ///
+ /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your
+ /// MSRV is lower.
+ pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self {
+ self.options.manually_drop_union.insert(arg);
+ self
+ }
+ }
+
+ fn_with_regex_arg! {
+ /// Add a string to prepend to the generated bindings. The string is passed
+ /// through without any modification.
+ pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.raw_lines.push(arg.into());
+ self
+ }
+ }
+
/// Add a given line to the beginning of module `mod`.
pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self
where
@@ -1336,17 +1453,6 @@ impl Builder {
self
}
- /// Avoid generating any unstable Rust, such as Rust unions, in the generated bindings.
- #[deprecated(note = "please use `rust_target` instead")]
- pub fn unstable_rust(self, doit: bool) -> Self {
- let rust_target = if doit {
- RustTarget::Nightly
- } else {
- LATEST_STABLE_RUST
- };
- self.rust_target(rust_target)
- }
-
/// Use core instead of libstd in the generated bindings.
pub fn use_core(mut self) -> Builder {
self.options.use_core = true;
@@ -1371,7 +1477,7 @@ impl Builder {
mut self,
cb: Box<dyn callbacks::ParseCallbacks>,
) -> Self {
- self.options.parse_callbacks = Some(cb);
+ self.options.parse_callbacks.push(Rc::from(cb));
self
}
@@ -1443,39 +1549,48 @@ impl Builder {
self
}
+ /// If true, enables experimental support to generate vtable functions.
+ ///
+ /// Should mostly work, though some edge cases are likely to be broken.
+ pub fn vtable_generation(mut self, doit: bool) -> Self {
+ self.options.vtable_generation = doit;
+ self
+ }
+
+ /// If true, enables the sorting of the output in a predefined manner.
+ ///
+ /// TODO: Perhaps move the sorting order out into a config
+ pub fn sort_semantically(mut self, doit: bool) -> Self {
+ self.options.sort_semantically = doit;
+ self
+ }
+
+ /// If true, merges extern blocks.
+ pub fn merge_extern_blocks(mut self, doit: bool) -> Self {
+ self.options.merge_extern_blocks = doit;
+ self
+ }
+
/// Generate the Rust bindings using the options built up thus far.
- pub fn generate(mut self) -> Result<Bindings, ()> {
+ pub fn generate(mut self) -> Result<Bindings, BindgenError> {
// Add any extra arguments from the environment to the clang command line.
- if let Some(extra_clang_args) =
- get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS")
- {
- // Try to parse it with shell quoting. If we fail, make it one single big argument.
- if let Some(strings) = shlex::split(&extra_clang_args) {
- self.options.clang_args.extend(strings);
- } else {
- self.options.clang_args.push(extra_clang_args);
- };
- }
+ self.options.clang_args.extend(get_extra_clang_args());
// Transform input headers to arguments on the clang command line.
- self.options.input_header = self.input_headers.pop();
- self.options.extra_input_headers = self.input_headers;
self.options.clang_args.extend(
- self.options.extra_input_headers.iter().flat_map(|header| {
- iter::once("-include".into())
- .chain(iter::once(header.to_string()))
- }),
+ self.options.input_headers
+ [..self.options.input_headers.len().saturating_sub(1)]
+ .iter()
+ .flat_map(|header| ["-include".into(), header.to_string()]),
);
- self.options.input_unsaved_files.extend(
- self.input_header_contents
- .drain(..)
- .map(|(name, contents)| {
- clang::UnsavedFile::new(&name, &contents)
- }),
- );
+ let input_unsaved_files =
+ std::mem::take(&mut self.options.input_header_contents)
+ .into_iter()
+ .map(|(name, contents)| clang::UnsavedFile::new(name, contents))
+ .collect::<Vec<_>>();
- Bindings::generate(self.options)
+ Bindings::generate(self.options, input_unsaved_files)
}
/// Preprocess and dump the input header files to disk.
@@ -1500,7 +1615,7 @@ impl Builder {
let mut is_cpp = args_are_cpp(&self.options.clang_args);
// For each input header, add `#include "$header"`.
- for header in &self.input_headers {
+ for header in &self.options.input_headers {
is_cpp |= file_is_cpp(header);
wrapper_contents.push_str("#include \"");
@@ -1510,7 +1625,7 @@ impl Builder {
// For each input header content, add a prefix line of `#line 0 "$name"`
// followed by the contents.
- for &(ref name, ref contents) in &self.input_header_contents {
+ for (name, contents) in &self.options.input_header_contents {
is_cpp |= file_is_cpp(name);
wrapper_contents.push_str("#line 0 \"");
@@ -1530,7 +1645,7 @@ impl Builder {
wrapper_file.write_all(wrapper_contents.as_bytes())?;
}
- let mut cmd = Command::new(&clang.path);
+ let mut cmd = Command::new(clang.path);
cmd.arg("-save-temps")
.arg("-E")
.arg("-C")
@@ -1542,6 +1657,10 @@ impl Builder {
cmd.arg(a);
}
+ for a in get_extra_clang_args() {
+ cmd.arg(a);
+ }
+
let mut child = cmd.spawn()?;
let mut preprocessed = child.stdout.take().unwrap();
@@ -1562,46 +1681,58 @@ impl Builder {
}
}
- /// Don't derive `PartialEq` for a given type. Regular
- /// expressions are supported.
- pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.no_partialeq_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Don't derive `PartialEq` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.no_partialeq_types.insert(arg.into());
+ self
+ }
}
- /// Don't derive `Copy` for a given type. Regular
- /// expressions are supported.
- pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_copy_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Don't derive `Copy` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_copy_types.insert(arg.into());
+ self
+ }
}
- /// Don't derive `Debug` for a given type. Regular
- /// expressions are supported.
- pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_debug_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Don't derive `Debug` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_debug_types.insert(arg.into());
+ self
+ }
}
- /// Don't derive/impl `Default` for a given type. Regular
- /// expressions are supported.
- pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self {
- self.options.no_default_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Don't derive/impl `Default` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self {
+ self.options.no_default_types.insert(arg.into());
+ self
+ }
}
- /// Don't derive `Hash` for a given type. Regular
- /// expressions are supported.
- pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.no_hash_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Don't derive `Hash` for a given type. Regular
+ /// expressions are supported.
+ pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.no_hash_types.insert(arg.into());
+ self
+ }
}
- /// Add `#[must_use]` for the given type. Regular
- /// expressions are supported.
- pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder {
- self.options.must_use_types.insert(arg.into());
- self
+ fn_with_regex_arg! {
+ /// Add `#[must_use]` for the given type. Regular
+ /// expressions are supported.
+ pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder {
+ self.options.must_use_types.insert(arg.into());
+ self
+ }
}
/// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut)
@@ -1660,10 +1791,52 @@ impl Builder {
self.options.c_naming = doit;
self
}
+
+ /// Override the ABI of a given function. Regular expressions are supported.
+ 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
+ }
+
+ /// If true, wraps unsafe operations in unsafe blocks.
+ pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self {
+ self.options.wrap_unsafe_ops = doit;
+ self
+ }
+
+ #[cfg(feature = "experimental")]
+ /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to
+ /// false.
+ pub fn wrap_static_fns(mut self, doit: bool) -> Self {
+ self.options.wrap_static_fns = doit;
+ self
+ }
+
+ #[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.
+ 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
+ }
+
+ #[cfg(feature = "experimental")]
+ /// Set the suffix added to the extern wrapper functions generated for `static` and `static
+ /// inline` functions.
+ 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
+ }
}
/// Configuration options for generated bindings.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
struct BindgenOptions {
/// The set of types that have been blocklisted and should not appear
/// anywhere in the generated code.
@@ -1705,6 +1878,9 @@ struct BindgenOptions {
/// Allowlisted variables. See docs for `allowlisted_types` for more.
allowlisted_vars: RegexSet,
+ /// The set of files whose contents should be allowlisted.
+ allowlisted_files: RegexSet,
+
/// The default style of code to generate for enums
default_enum_style: codegen::EnumVariation,
@@ -1715,6 +1891,9 @@ struct BindgenOptions {
/// The enum patterns to mark an enum as a newtype.
newtype_enums: RegexSet,
+ /// The enum patterns to mark an enum as a global newtype.
+ newtype_global_enums: RegexSet,
+
/// The enum patterns to mark an enum as a Rust enum.
rustified_enums: RegexSet,
@@ -1743,6 +1922,18 @@ struct BindgenOptions {
/// Deref and Deref to their aliased type.
new_type_alias_deref: RegexSet,
+ /// The default style of code to generate for union containing non-Copy
+ /// members.
+ default_non_copy_union_style: codegen::NonCopyUnionStyle,
+
+ /// The union patterns to mark an non-Copy union as using the bindgen
+ /// generated wrapper.
+ bindgen_wrapper_union: RegexSet,
+
+ /// The union patterns to mark an non-Copy union as using the
+ /// `::core::mem::ManuallyDrop` wrapper.
+ manually_drop_union: RegexSet,
+
/// Whether we should generate builtins or not.
builtins: bool,
@@ -1827,13 +2018,6 @@ struct BindgenOptions {
/// Whether to time the bindgen phases.
time_phases: bool,
- /// True if we should generate constant names that are **directly** under
- /// namespaces.
- namespaced_constants: bool,
-
- /// True if we should use MSVC name mangling rules.
- msvc_mangling: bool,
-
/// Whether we should convert float types to f32/f64 types.
convert_floats: bool,
@@ -1849,18 +2033,15 @@ struct BindgenOptions {
/// The set of arguments to pass straight through to Clang.
clang_args: Vec<String>,
- /// The input header file.
- input_header: Option<String>,
-
- /// Any additional input header files.
- extra_input_headers: Vec<String>,
+ /// The input header files.
+ input_headers: Vec<String>,
- /// Unsaved files for input.
- input_unsaved_files: Vec<clang::UnsavedFile>,
+ /// Tuples of unsaved file contents of the form (name, contents).
+ input_header_contents: Vec<(String, String)>,
/// A user-provided visitor to allow customizing different kinds of
/// situations.
- parse_callbacks: Option<Box<dyn callbacks::ParseCallbacks>>,
+ parse_callbacks: Vec<Rc<dyn callbacks::ParseCallbacks>>,
/// Which kind of items should we generate? By default, we'll generate all
/// of them.
@@ -1978,19 +2159,35 @@ struct BindgenOptions {
/// Always output explicit padding fields
force_explicit_padding: bool,
-}
-/// TODO(emilio): This is sort of a lie (see the error message that results from
-/// removing this), but since we don't share references across panic boundaries
-/// it's ok.
-impl ::std::panic::UnwindSafe for BindgenOptions {}
+ /// Emit vtable functions.
+ vtable_generation: bool,
+
+ /// Sort the code generation.
+ sort_semantically: bool,
+
+ /// Deduplicate `extern` blocks.
+ merge_extern_blocks: bool,
+
+ abi_overrides: HashMap<Abi, RegexSet>,
+
+ /// Whether to wrap unsafe operations in unsafe blocks or not.
+ wrap_unsafe_ops: bool,
+
+ wrap_static_fns: bool,
+
+ wrap_static_fns_suffix: Option<String>,
+
+ wrap_static_fns_path: Option<PathBuf>,
+}
impl BindgenOptions {
fn build(&mut self) {
- let mut regex_sets = [
+ let regex_sets = [
&mut self.allowlisted_vars,
&mut self.allowlisted_types,
&mut self.allowlisted_functions,
+ &mut self.allowlisted_files,
&mut self.blocklisted_types,
&mut self.blocklisted_functions,
&mut self.blocklisted_items,
@@ -2000,11 +2197,14 @@ impl BindgenOptions {
&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,
@@ -2013,7 +2213,7 @@ impl BindgenOptions {
&mut self.must_use_types,
];
let record_matches = self.record_matches;
- for regex_set in &mut regex_sets {
+ for regex_set in self.abi_overrides.values_mut().chain(regex_sets) {
regex_set.build(record_matches);
}
}
@@ -2030,101 +2230,150 @@ impl BindgenOptions {
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 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)
+ }
}
impl Default for BindgenOptions {
fn default() -> BindgenOptions {
+ macro_rules! options {
+ ($($field:ident $(: $value:expr)?,)* --default-fields-- $($default_field:ident,)*) => {
+ BindgenOptions {
+ $($field $(: $value)*,)*
+ $($default_field: Default::default(),)*
+ }
+ };
+ }
+
let rust_target = RustTarget::default();
- BindgenOptions {
+ options! {
rust_target,
rust_features: rust_target.into(),
- blocklisted_types: Default::default(),
- blocklisted_functions: Default::default(),
- blocklisted_items: Default::default(),
- blocklisted_files: Default::default(),
- opaque_types: Default::default(),
- rustfmt_path: Default::default(),
- depfile: Default::default(),
- allowlisted_types: Default::default(),
- allowlisted_functions: Default::default(),
- allowlisted_vars: Default::default(),
- default_enum_style: Default::default(),
- bitfield_enums: Default::default(),
- newtype_enums: Default::default(),
- rustified_enums: Default::default(),
- rustified_non_exhaustive_enums: Default::default(),
- constified_enums: Default::default(),
- constified_enum_modules: Default::default(),
- default_macro_constant_type: Default::default(),
- default_alias_style: Default::default(),
- type_alias: Default::default(),
- new_type_alias: Default::default(),
- new_type_alias_deref: Default::default(),
- builtins: false,
- emit_ast: false,
- emit_ir: false,
- emit_ir_graphviz: None,
layout_tests: true,
- impl_debug: false,
- impl_partialeq: false,
derive_copy: true,
derive_debug: true,
- derive_default: false,
- derive_hash: false,
- derive_partialord: false,
- derive_ord: false,
- derive_partialeq: false,
- derive_eq: false,
- enable_cxx_namespaces: false,
- enable_function_attribute_detection: false,
- disable_name_namespacing: false,
- disable_nested_struct_naming: false,
- disable_header_comment: false,
- use_core: false,
- ctypes_prefix: None,
anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(),
- namespaced_constants: true,
- msvc_mangling: false,
convert_floats: true,
- raw_lines: vec![],
- module_lines: HashMap::default(),
- clang_args: vec![],
- input_header: None,
- extra_input_headers: vec![],
- input_unsaved_files: vec![],
- parse_callbacks: None,
codegen_config: CodegenConfig::all(),
- conservative_inline_namespaces: false,
generate_comments: true,
- generate_inline_functions: false,
allowlist_recursively: true,
- generate_block: false,
- objc_extern_crate: false,
- block_extern_crate: false,
enable_mangling: true,
detect_include_paths: true,
- fit_macro_constants: false,
prepend_enum_name: true,
- time_phases: false,
record_matches: true,
rustfmt_bindings: true,
- size_t_is_usize: false,
- rustfmt_configuration_file: None,
- no_partialeq_types: Default::default(),
- no_copy_types: Default::default(),
- no_debug_types: Default::default(),
- no_default_types: Default::default(),
- no_hash_types: Default::default(),
- must_use_types: Default::default(),
- array_pointers_in_arguments: false,
- wasm_import_module_name: None,
- dynamic_library_name: None,
- dynamic_link_require_all: false,
- respect_cxx_access_specs: false,
- translate_enum_integer_types: false,
- c_naming: false,
- force_explicit_padding: false,
+ size_t_is_usize: true,
+
+ --default-fields--
+ blocklisted_types,
+ blocklisted_functions,
+ blocklisted_items,
+ blocklisted_files,
+ opaque_types,
+ rustfmt_path,
+ depfile,
+ allowlisted_types,
+ allowlisted_functions,
+ allowlisted_vars,
+ allowlisted_files,
+ default_enum_style,
+ bitfield_enums,
+ newtype_enums,
+ newtype_global_enums,
+ rustified_enums,
+ rustified_non_exhaustive_enums,
+ constified_enums,
+ constified_enum_modules,
+ default_macro_constant_type,
+ default_alias_style,
+ type_alias,
+ new_type_alias,
+ new_type_alias_deref,
+ default_non_copy_union_style,
+ bindgen_wrapper_union,
+ manually_drop_union,
+ builtins,
+ emit_ast,
+ emit_ir,
+ emit_ir_graphviz,
+ impl_debug,
+ impl_partialeq,
+ derive_default,
+ derive_hash,
+ derive_partialord,
+ derive_ord,
+ derive_partialeq,
+ derive_eq,
+ enable_cxx_namespaces,
+ enable_function_attribute_detection,
+ disable_name_namespacing,
+ disable_nested_struct_naming,
+ disable_header_comment,
+ use_core,
+ ctypes_prefix,
+ raw_lines,
+ module_lines,
+ clang_args,
+ input_headers,
+ input_header_contents,
+ parse_callbacks,
+ conservative_inline_namespaces,
+ generate_inline_functions,
+ generate_block,
+ objc_extern_crate,
+ block_extern_crate,
+ fit_macro_constants,
+ time_phases,
+ rustfmt_configuration_file,
+ no_partialeq_types,
+ no_copy_types,
+ no_debug_types,
+ no_default_types,
+ no_hash_types,
+ must_use_types,
+ array_pointers_in_arguments,
+ wasm_import_module_name,
+ dynamic_library_name,
+ dynamic_link_require_all,
+ respect_cxx_access_specs,
+ translate_enum_integer_types,
+ c_naming,
+ force_explicit_padding,
+ vtable_generation,
+ sort_semantically,
+ merge_extern_blocks,
+ abi_overrides,
+ wrap_unsafe_ops,
+ wrap_static_fns,
+ wrap_static_fns_suffix,
+ wrap_static_fns_path,
}
}
}
@@ -2155,10 +2404,51 @@ fn ensure_libclang_is_loaded() {
#[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,
+ warnings: Vec<String>,
module: proc_macro2::TokenStream,
}
@@ -2173,6 +2463,19 @@ fn rust_to_clang_target(rust_target: &str) -> String {
clang_target
.push_str(rust_target.strip_prefix("aarch64-apple-").unwrap());
return clang_target;
+ } else if rust_target.starts_with("riscv64gc-") {
+ let mut clang_target = "riscv64-".to_owned();
+ clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap());
+ return clang_target;
+ } 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;
}
rust_target.to_owned()
}
@@ -2207,7 +2510,8 @@ impl Bindings {
/// Generate bindings for the given options.
pub(crate) fn generate(
mut options: BindgenOptions,
- ) -> Result<Bindings, ()> {
+ input_unsaved_files: Vec<clang::UnsavedFile>,
+ ) -> Result<Bindings, BindgenError> {
ensure_libclang_is_loaded();
#[cfg(feature = "runtime")]
@@ -2293,7 +2597,7 @@ impl Bindings {
// Whether we are working with C or C++ inputs.
let is_cpp = args_are_cpp(&options.clang_args) ||
- options.input_header.as_deref().map_or(false, file_is_cpp);
+ options.input_headers.iter().any(|h| file_is_cpp(h));
let search_paths = if is_cpp {
clang.cpp_search_paths
@@ -2324,28 +2628,26 @@ impl Bindings {
true
}
- if let Some(h) = options.input_header.as_ref() {
- if let Ok(md) = std::fs::metadata(h) {
+ if let Some(h) = options.input_headers.last() {
+ let path = Path::new(h);
+ if let Ok(md) = std::fs::metadata(path) {
if md.is_dir() {
- eprintln!("error: '{}' is a folder", h);
- return Err(());
+ return Err(BindgenError::FolderAsHeader(path.into()));
}
if !can_read(&md.permissions()) {
- eprintln!(
- "error: insufficient permissions to read '{}'",
- h
- );
- return Err(());
+ return Err(BindgenError::InsufficientPermissions(
+ path.into(),
+ ));
}
- options.clang_args.push(h.clone())
+ let h = h.clone();
+ options.clang_args.push(h);
} else {
- eprintln!("error: header '{}' does not exist.", h);
- return Err(());
+ return Err(BindgenError::NotExist(path.into()));
}
}
- for (idx, f) in options.input_unsaved_files.iter().enumerate() {
- if idx != 0 || options.input_header.is_some() {
+ for (idx, f) in input_unsaved_files.iter().enumerate() {
+ if idx != 0 || !options.input_headers.is_empty() {
options.clang_args.push("-include".to_owned());
}
options.clang_args.push(f.name.to_str().unwrap().to_owned())
@@ -2354,7 +2656,7 @@ impl Bindings {
debug!("Fixed-up options: {:?}", options);
let time_phases = options.time_phases;
- let mut context = BindgenContext::new(options);
+ let mut context = BindgenContext::new(options, &input_unsaved_files);
if is_host_build {
debug_assert_eq!(
@@ -2371,13 +2673,13 @@ impl Bindings {
parse(&mut context)?;
}
- let (items, options) = codegen::codegen(context);
+ let (module, options, warnings) =
+ codegen::codegen(context).map_err(BindgenError::Codegen)?;
Ok(Bindings {
options,
- module: quote! {
- #( #items )*
- },
+ warnings,
+ module,
})
}
@@ -2395,7 +2697,7 @@ impl Bindings {
/// Write these bindings as source text to the given `Write`able.
pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
if !self.options.disable_header_comment {
- let version = Some("0.59.2");
+ let version = Some("0.64.0");
let header = format!(
"/* automatically generated by rust-bindgen {} */\n\n",
version.unwrap_or("(unknown version)")
@@ -2474,7 +2776,7 @@ impl Bindings {
.as_ref()
.and_then(|f| f.to_str())
{
- cmd.args(&["--config-path", path]);
+ cmd.args(["--config-path", path]);
}
let mut child = cmd.spawn()?;
@@ -2519,6 +2821,23 @@ impl Bindings {
_ => Ok(Cow::Owned(source)),
}
}
+
+ /// Emit all the warning messages raised while generating the bindings in a build script.
+ ///
+ /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`]
+ /// and handle the messages accordingly instead.
+ #[inline]
+ pub fn emit_warnings(&self) {
+ for message in &self.warnings {
+ println!("cargo:warning={}", message);
+ }
+ }
+
+ /// Return all the warning messages raised while generating the bindings.
+ #[inline]
+ pub fn warnings(&self) -> &[String] {
+ &self.warnings
+ }
}
impl std::fmt::Display for Bindings {
@@ -2561,19 +2880,24 @@ fn parse_one(
}
/// Parse the Clang AST into our `Item` internal representation.
-fn parse(context: &mut BindgenContext) -> Result<(), ()> {
+fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> {
use clang_sys::*;
- let mut any_error = false;
+ let mut error = None;
for d in context.translation_unit().diags().iter() {
let msg = d.format();
let is_err = d.severity() >= CXDiagnostic_Error;
- eprintln!("{}, err: {}", msg, is_err);
- any_error |= is_err;
+ if is_err {
+ let error = error.get_or_insert_with(String::new);
+ error.push_str(&msg);
+ error.push('\n');
+ } else {
+ eprintln!("clang diag: {}", msg);
+ }
}
- if any_error {
- return Err(());
+ if let Some(message) = error {
+ return Err(BindgenError::ClangDiagnostic(message));
}
let cursor = context.translation_unit().cursor();
@@ -2641,11 +2965,10 @@ pub fn clang_version() -> ClangVersion {
/// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found.
fn get_target_dependent_env_var(var: &str) -> Option<String> {
if let Ok(target) = env::var("TARGET") {
- if let Ok(v) = env::var(&format!("{}_{}", var, target)) {
+ if let Ok(v) = env::var(format!("{}_{}", var, target)) {
return Some(v);
}
- if let Ok(v) =
- env::var(&format!("{}_{}", var, target.replace("-", "_")))
+ if let Ok(v) = env::var(format!("{}_{}", var, target.replace('-', "_")))
{
return Some(v);
}
@@ -2691,9 +3014,7 @@ fn commandline_flag_unit_test_function() {
.map(|&x| x.into())
.collect::<Vec<String>>();
- assert!(test_cases
- .iter()
- .all(|ref x| command_line_flags.contains(x),));
+ assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
//Test 2
let bindings = crate::builder()
@@ -2718,12 +3039,30 @@ fn commandline_flag_unit_test_function() {
.collect::<Vec<String>>();
println!("{:?}", command_line_flags);
- assert!(test_cases
- .iter()
- .all(|ref x| command_line_flags.contains(x),));
+ assert!(test_cases.iter().all(|x| command_line_flags.contains(x)));
}
#[test]
fn test_rust_to_clang_target() {
assert_eq!(rust_to_clang_target("aarch64-apple-ios"), "arm64-apple-ios");
}
+
+#[test]
+fn test_rust_to_clang_target_riscv() {
+ assert_eq!(
+ rust_to_clang_target("riscv64gc-unknown-linux-gnu"),
+ "riscv64-unknown-linux-gnu"
+ )
+}
+
+#[test]
+fn test_rust_to_clang_target_espidf() {
+ assert_eq!(
+ rust_to_clang_target("riscv32imc-esp-espidf"),
+ "riscv32-esp-elf"
+ );
+ assert_eq!(
+ rust_to_clang_target("xtensa-esp32-espidf"),
+ "xtensa-esp32-elf"
+ );
+}
diff --git a/src/log_stubs.rs b/log_stubs.rs
index 8315983..8315983 100644
--- a/src/log_stubs.rs
+++ b/log_stubs.rs
diff --git a/out/tests.rs b/out/tests.rs
deleted file mode 100644
index e69de29..0000000
--- a/out/tests.rs
+++ /dev/null
diff --git a/parse.rs b/parse.rs
new file mode 100644
index 0000000..1fd83cd
--- /dev/null
+++ b/parse.rs
@@ -0,0 +1,40 @@
+//! Common traits and types related to parsing our IR from Clang cursors.
+
+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 enum ParseError {
+ /// Recurse down the current AST node's children.
+ Recurse,
+ /// Continue on to the next sibling AST node, or back up to the parent's
+ /// siblings if we've exhausted all of this node's siblings (and so on).
+ Continue,
+}
+
+/// The result of parsing a Clang AST node.
+#[derive(Debug)]
+pub enum ParseResult<T> {
+ /// We've already resolved this item before, here is the extant `ItemId` for
+ /// it.
+ AlreadyResolved(ItemId),
+
+ /// This is a newly parsed item. If the cursor is `Some`, it points to the
+ /// AST node where the new `T` was declared.
+ New(T, Option<clang::Cursor>),
+}
+
+/// An intermediate representation "sub-item" (i.e. one of the types contained
+/// inside an `ItemKind` variant) that can be parsed from a Clang cursor.
+pub trait ClangSubItemParser: Sized {
+ /// Attempt to parse this type from the given cursor.
+ ///
+ /// The fact that is a reference guarantees it's held by the context, and
+ /// allow returning already existing types.
+ fn parse(
+ cursor: clang::Cursor,
+ context: &mut BindgenContext,
+ ) -> Result<ParseResult<Self>, ParseError>;
+}
diff --git a/patches/Android.bp.diff b/patches/Android.bp.diff
new file mode 100644
index 0000000..0e9e66e
--- /dev/null
+++ b/patches/Android.bp.diff
@@ -0,0 +1,13 @@
+diff --git a/Android.bp b/Android.bp
+index fd57489..86a6c71 100644
+--- a/Android.bp
++++ b/Android.bp
+@@ -56,7 +56,7 @@ rust_library_host {
+ "which-rustfmt",
+ ],
+ rustlibs: [
+- "libbitflags",
++ "libbitflags-1.3.2",
+ "libcexpr",
+ "libclang_sys",
+ "liblazy_static",
diff --git a/patches/bindgen_cmd.diff b/patches/bindgen_cmd.diff
new file mode 100644
index 0000000..9b28ff7
--- /dev/null
+++ b/patches/bindgen_cmd.diff
@@ -0,0 +1,90 @@
+diff --git a/android/bindgen_cmd/Android.bp b/android/bindgen_cmd/Android.bp
+new file mode 100644
+index 0000000..689e7ae
+--- /dev/null
++++ b/android/bindgen_cmd/Android.bp
+@@ -0,0 +1,28 @@
++package {
++ // See: http://go/android-license-faq
++ // A large-scale-change added 'default_applicable_licenses' to import
++ // all of the 'license_kinds' from "external_rust_crates_bindgen_license"
++ // to get the below license kinds:
++ // SPDX-license-identifier-Apache-2.0
++ default_applicable_licenses: ["external_rust_crates_bindgen_license"],
++}
++
++rust_library_host {
++ name: "libbindgen_cmd",
++ crate_name: "bindgen_cmd",
++ srcs: ["src/lib.rs"],
++ edition: "2018",
++ features: [
++ "clap",
++ "runtime",
++ "which",
++ "which-rustfmt",
++ ],
++ rustlibs: [
++ "libbindgen",
++ "libbindgen_cli",
++ "libclap",
++ "libenv_logger",
++ ],
++ compile_multilib: "first",
++}
+diff --git a/android/bindgen_cmd/src/lib.rs b/android/bindgen_cmd/src/lib.rs
+new file mode 100644
+index 0000000..d33da7f
+--- /dev/null
++++ b/android/bindgen_cmd/src/lib.rs
+@@ -0,0 +1,50 @@
++// Copyright 2020, The Android Open Source Project
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++
++//! This is a helper crate for using bindgen as a library from within
++//! Android's build system. Some functionality (such as the type selection
++//! heuristic) is not available on the command line, and so the library
++//! interface may be necessary. Bindgen also needs to receive configuration
++//! from Soong however to find appropriate headers, set global cflags, etc.
++//!
++//! This crate provides the ability to run a hooked version of the command
++//! line bindgen tool, with the ability to call a user-provided transformation
++//! on the the builder before it is used.
++
++use bindgen;
++use bindgen_cli;
++use std::env;
++
++/// Takes in a function describing adjustments to make to a builder
++/// initialized by the command line. `build(|x| x)` is equivalent to
++/// running bindgen. When converting a build.rs, you will want to convert the
++/// additional configuration they do into a function, then pass it to `build`
++/// inside your main function.
++pub fn build<C: FnOnce(bindgen::Builder) -> bindgen::Builder>(configure: C) {
++ env_logger::init();
++
++ match bindgen_cli::builder_from_flags(env::args()) {
++ Ok((builder, output, _)) => {
++ configure(builder)
++ .generate()
++ .expect("Unable to generate bindings")
++ .write(output)
++ .expect("Unable to write output");
++ }
++ Err(error) => {
++ eprintln!("{}", error);
++ std::process::exit(1);
++ }
++ };
++}
diff --git a/post_update.sh b/post_update.sh
deleted file mode 100755
index 52614aa..0000000
--- a/post_update.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-# $1 Path to the new version.
-# $2 Path to the old version.
-
-set -x
-set -e
-
-cp -a -n -r $2/android $1/
diff --git a/src/regex_set.rs b/regex_set.rs
index 127c001..6246dd2 100644
--- a/src/regex_set.rs
+++ b/regex_set.rs
@@ -4,7 +4,7 @@ use regex::RegexSet as RxSet;
use std::cell::Cell;
/// A dynamic set of regular expressions.
-#[derive(Debug, Default)]
+#[derive(Clone, Debug, Default)]
pub struct RegexSet {
items: Vec<String>,
/// Whether any of the items in the set was ever matched. The length of this
@@ -16,6 +16,13 @@ pub struct RegexSet {
}
impl RegexSet {
+ /// Create a new RegexSet
+ pub fn new() -> RegexSet {
+ RegexSet {
+ ..Default::default()
+ }
+ }
+
/// Is this set empty?
pub fn is_empty(&self) -> bool {
self.items.is_empty()
@@ -26,7 +33,11 @@ impl RegexSet {
where
S: AsRef<str>,
{
- self.items.push(string.as_ref().to_owned());
+ let string = string.as_ref().to_owned();
+ if string == "*" {
+ warn!("using wildcard patterns (`*`) is no longer considered valid. Use `.*` instead");
+ }
+ self.items.push(string);
self.matched.push(Cell::new(false));
self.set = None;
}
@@ -53,7 +64,7 @@ impl RegexSet {
/// Must be called before calling `matches()`, or it will always return
/// false.
pub fn build(&mut self, record_matches: bool) {
- let items = self.items.iter().map(|item| format!("^{}$", item));
+ let items = self.items.iter().map(|item| format!("^({})$", item));
self.record_matches = record_matches;
self.set = match RxSet::new(items) {
Ok(x) => Some(x),
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index f3398db..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-extern crate bindgen;
-#[cfg(feature = "logging")]
-extern crate env_logger;
-#[macro_use]
-#[cfg(feature = "logging")]
-extern crate log;
-extern crate clap;
-
-use bindgen::clang_version;
-use std::env;
-use std::panic;
-
-#[macro_use]
-#[cfg(not(feature = "logging"))]
-mod log_stubs;
-
-mod options;
-use crate::options::builder_from_flags;
-
-fn clang_version_check() {
- let version = clang_version();
- let expected_version = if cfg!(feature = "testing_only_libclang_9") {
- Some((9, 0))
- } else if cfg!(feature = "testing_only_libclang_5") {
- Some((5, 0))
- } else if cfg!(feature = "testing_only_libclang_4") {
- Some((4, 0))
- } else if cfg!(feature = "testing_only_libclang_3_9") {
- Some((3, 9))
- } else {
- None
- };
-
- info!(
- "Clang Version: {}, parsed: {:?}",
- version.full, version.parsed
- );
-
- if expected_version.is_some() {
- // assert_eq!(version.parsed, version.parsed);
- }
-}
-
-pub fn main() {
- #[cfg(feature = "logging")]
- env_logger::init();
-
- match builder_from_flags(env::args()) {
- Ok((builder, output, verbose)) => {
- clang_version_check();
- let builder_result = panic::catch_unwind(|| {
- builder.generate().expect("Unable to generate bindings")
- });
-
- if builder_result.is_err() {
- if verbose {
- print_verbose_err();
- }
- std::process::exit(1);
- }
-
- let bindings = builder_result.unwrap();
- bindings.write(output).expect("Unable to write output");
- }
- Err(error) => {
- println!("{}", error);
- std::process::exit(1);
- }
- };
-}
-
-fn print_verbose_err() {
- println!("Bindgen unexpectedly panicked");
- println!(
- "This may be caused by one of the known-unsupported \
- things (https://rust-lang.github.io/rust-bindgen/cpp.html), \
- please modify the bindgen flags to work around it as \
- described in https://rust-lang.github.io/rust-bindgen/cpp.html"
- );
- println!(
- "Otherwise, please file an issue at \
- https://github.com/rust-lang/rust-bindgen/issues/new"
- );
-}
-
-#[cfg(test)]
-mod test {
- fn build_flags_output_helper(builder: &bindgen::Builder) {
- let mut command_line_flags = builder.command_line_flags();
- command_line_flags.insert(0, "bindgen".to_string());
-
- let flags_quoted: Vec<String> = command_line_flags
- .iter()
- .map(|x| format!("{}", shlex::quote(x)))
- .collect();
- let flags_str = flags_quoted.join(" ");
- println!("{}", flags_str);
-
- let (builder, _output, _verbose) =
- crate::options::builder_from_flags(command_line_flags.into_iter())
- .unwrap();
- builder.generate().expect("failed to generate bindings");
- }
-
- #[test]
- fn commandline_multiple_headers() {
- let bindings = bindgen::Builder::default()
- .header("tests/headers/char.h")
- .header("tests/headers/func_ptr.h")
- .header("tests/headers/16-byte-alignment.h");
- build_flags_output_helper(&bindings);
- }
-}
diff --git a/src/options.rs b/src/options.rs
deleted file mode 100644
index 94f3047..0000000
--- a/src/options.rs
+++ /dev/null
@@ -1,1000 +0,0 @@
-use bindgen::{
- builder, AliasVariation, Builder, CodegenConfig, EnumVariation,
- MacroTypeVariation, RustTarget, DEFAULT_ANON_FIELDS_PREFIX,
- RUST_TARGET_STRINGS,
-};
-use clap::{App, Arg};
-use std::fs::File;
-use std::io::{self, stderr, Error, ErrorKind, Write};
-use std::path::PathBuf;
-use std::str::FromStr;
-
-/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
-pub fn builder_from_flags<I>(
- args: I,
-) -> Result<(Builder, Box<dyn io::Write>, bool), io::Error>
-where
- I: Iterator<Item = String>,
-{
- let rust_target_help = format!(
- "Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.",
- RUST_TARGET_STRINGS,
- String::from(RustTarget::default())
- );
-
- let matches = App::new("bindgen")
- .version(Some("0.59.2").unwrap_or("unknown"))
- .about("Generates Rust bindings from C/C++ headers.")
- .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
- .args(&[
- Arg::with_name("header")
- .help("C or C++ header file")
- .required(true),
- Arg::with_name("depfile")
- .long("depfile")
- .takes_value(true)
- .help("Path to write depfile to"),
- Arg::with_name("default-enum-style")
- .long("default-enum-style")
- .help("The default style of code used to generate enums.")
- .value_name("variant")
- .default_value("consts")
- .possible_values(&[
- "consts",
- "moduleconsts",
- "bitfield",
- "newtype",
- "rust",
- "rust_non_exhaustive",
- ])
- .multiple(false),
- Arg::with_name("bitfield-enum")
- .long("bitfield-enum")
- .help(
- "Mark any enum whose name matches <regex> as a set of \
- bitfield flags.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("newtype-enum")
- .long("newtype-enum")
- .help("Mark any enum whose name matches <regex> as a newtype.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("rustified-enum")
- .long("rustified-enum")
- .help("Mark any enum whose name matches <regex> as a Rust enum.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("constified-enum")
- .long("constified-enum")
- .help(
- "Mark any enum whose name matches <regex> as a series of \
- constants.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("constified-enum-module")
- .long("constified-enum-module")
- .help(
- "Mark any enum whose name matches <regex> as a module of \
- constants.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("default-macro-constant-type")
- .long("default-macro-constant-type")
- .help("The default signed/unsigned type for C macro constants.")
- .value_name("variant")
- .default_value("unsigned")
- .possible_values(&["signed", "unsigned"])
- .multiple(false),
- Arg::with_name("default-alias-style")
- .long("default-alias-style")
- .help("The default style of code used to generate typedefs.")
- .value_name("variant")
- .default_value("type_alias")
- .possible_values(&[
- "type_alias",
- "new_type",
- "new_type_deref",
- ])
- .multiple(false),
- Arg::with_name("normal-alias")
- .long("normal-alias")
- .help(
- "Mark any typedef alias whose name matches <regex> to use \
- normal type aliasing.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("new-type-alias")
- .long("new-type-alias")
- .help(
- "Mark any typedef alias whose name matches <regex> to have \
- a new type generated for it.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("new-type-alias-deref")
- .long("new-type-alias-deref")
- .help(
- "Mark any typedef alias whose name matches <regex> to have \
- a new type with Deref and DerefMut to the inner type.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("blocklist-type")
- .alias("blacklist-type")
- .long("blocklist-type")
- .help("Mark <type> as hidden.")
- .value_name("type")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("blocklist-function")
- .alias("blacklist-function")
- .long("blocklist-function")
- .help("Mark <function> as hidden.")
- .value_name("function")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("blocklist-item")
- .alias("blacklist-item")
- .long("blocklist-item")
- .help("Mark <item> as hidden.")
- .value_name("item")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("blocklist-file")
- .alias("blacklist-file")
- .long("blocklist-file")
- .help("Mark all contents of <path> as hidden.")
- .value_name("path")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("no-layout-tests")
- .long("no-layout-tests")
- .help("Avoid generating layout tests for any type."),
- Arg::with_name("no-derive-copy")
- .long("no-derive-copy")
- .help("Avoid deriving Copy on any type."),
- Arg::with_name("no-derive-debug")
- .long("no-derive-debug")
- .help("Avoid deriving Debug on any type."),
- Arg::with_name("no-derive-default")
- .long("no-derive-default")
- .hidden(true)
- .help("Avoid deriving Default on any type."),
- Arg::with_name("impl-debug").long("impl-debug").help(
- "Create Debug implementation, if it can not be derived \
- automatically.",
- ),
- Arg::with_name("impl-partialeq")
- .long("impl-partialeq")
- .help(
- "Create PartialEq implementation, if it can not be derived \
- automatically.",
- ),
- Arg::with_name("with-derive-default")
- .long("with-derive-default")
- .help("Derive Default on any type."),
- Arg::with_name("with-derive-hash")
- .long("with-derive-hash")
- .help("Derive hash on any type."),
- Arg::with_name("with-derive-partialeq")
- .long("with-derive-partialeq")
- .help("Derive partialeq on any type."),
- Arg::with_name("with-derive-partialord")
- .long("with-derive-partialord")
- .help("Derive partialord on any type."),
- Arg::with_name("with-derive-eq")
- .long("with-derive-eq")
- .help(
- "Derive eq on any type. Enable this option also \
- enables --with-derive-partialeq",
- ),
- Arg::with_name("with-derive-ord")
- .long("with-derive-ord")
- .help(
- "Derive ord on any type. Enable this option also \
- enables --with-derive-partialord",
- ),
- Arg::with_name("no-doc-comments")
- .long("no-doc-comments")
- .help(
- "Avoid including doc comments in the output, see: \
- https://github.com/rust-lang/rust-bindgen/issues/426",
- ),
- Arg::with_name("no-recursive-allowlist")
- .long("no-recursive-allowlist")
- .alias("no-recursive-whitelist")
- .help(
- "Disable allowlisting types recursively. This will cause \
- bindgen to emit Rust code that won't compile! See the \
- `bindgen::Builder::allowlist_recursively` method's \
- documentation for details.",
- ),
- Arg::with_name("objc-extern-crate")
- .long("objc-extern-crate")
- .help("Use extern crate instead of use for objc."),
- Arg::with_name("generate-block")
- .long("generate-block")
- .help("Generate block signatures instead of void pointers."),
- Arg::with_name("block-extern-crate")
- .long("block-extern-crate")
- .help("Use extern crate instead of use for block."),
- Arg::with_name("distrust-clang-mangling")
- .long("distrust-clang-mangling")
- .help("Do not trust the libclang-provided mangling"),
- Arg::with_name("builtins").long("builtins").help(
- "Output bindings for builtin definitions, e.g. \
- __builtin_va_list.",
- ),
- Arg::with_name("ctypes-prefix")
- .long("ctypes-prefix")
- .help(
- "Use the given prefix before raw types instead of \
- ::std::os::raw.",
- )
- .value_name("prefix")
- .takes_value(true),
- Arg::with_name("anon-fields-prefix")
- .long("anon-fields-prefix")
- .help("Use the given prefix for the anon fields.")
- .value_name("prefix")
- .default_value(DEFAULT_ANON_FIELDS_PREFIX)
- .takes_value(true),
- Arg::with_name("time-phases")
- .long("time-phases")
- .help("Time the different bindgen phases and print to stderr"),
- // All positional arguments after the end of options marker, `--`
- Arg::with_name("clang-args").last(true).multiple(true),
- Arg::with_name("emit-clang-ast")
- .long("emit-clang-ast")
- .help("Output the Clang AST for debugging purposes."),
- Arg::with_name("emit-ir")
- .long("emit-ir")
- .help("Output our internal IR for debugging purposes."),
- Arg::with_name("emit-ir-graphviz")
- .long("emit-ir-graphviz")
- .help("Dump graphviz dot file.")
- .value_name("path")
- .takes_value(true),
- Arg::with_name("enable-cxx-namespaces")
- .long("enable-cxx-namespaces")
- .help("Enable support for C++ namespaces."),
- Arg::with_name("disable-name-namespacing")
- .long("disable-name-namespacing")
- .help(
- "Disable namespacing via mangling, causing bindgen to \
- generate names like \"Baz\" instead of \"foo_bar_Baz\" \
- for an input name \"foo::bar::Baz\".",
- ),
- Arg::with_name("disable-nested-struct-naming")
- .long("disable-nested-struct-naming")
- .help(
- "Disable nested struct naming, causing bindgen to generate \
- names like \"bar\" instead of \"foo_bar\" for a nested \
- definition \"struct foo { struct bar { } b; };\"."
- ),
- Arg::with_name("disable-untagged-union")
- .long("disable-untagged-union")
- .help(
- "Disable support for native Rust unions.",
- ),
- Arg::with_name("disable-header-comment")
- .long("disable-header-comment")
- .help("Suppress insertion of bindgen's version identifier into generated bindings.")
- .multiple(true),
- Arg::with_name("ignore-functions")
- .long("ignore-functions")
- .help(
- "Do not generate bindings for functions or methods. This \
- is useful when you only care about struct layouts.",
- ),
- Arg::with_name("generate")
- .long("generate")
- .help(
- "Generate only given items, split by commas. \
- Valid values are \"functions\",\"types\", \"vars\", \
- \"methods\", \"constructors\" and \"destructors\".",
- )
- .takes_value(true),
- Arg::with_name("ignore-methods")
- .long("ignore-methods")
- .help("Do not generate bindings for methods."),
- Arg::with_name("no-convert-floats")
- .long("no-convert-floats")
- .help("Do not automatically convert floats to f32/f64."),
- Arg::with_name("no-prepend-enum-name")
- .long("no-prepend-enum-name")
- .help("Do not prepend the enum name to constant or newtype variants."),
- Arg::with_name("no-include-path-detection")
- .long("no-include-path-detection")
- .help("Do not try to detect default include paths"),
- Arg::with_name("fit-macro-constant-types")
- .long("fit-macro-constant-types")
- .help("Try to fit macro constants into types smaller than u32/i32"),
- Arg::with_name("unstable-rust")
- .long("unstable-rust")
- .help("Generate unstable Rust code (deprecated; use --rust-target instead).")
- .multiple(true), // FIXME: Pass legacy test suite
- Arg::with_name("opaque-type")
- .long("opaque-type")
- .help("Mark <type> as opaque.")
- .value_name("type")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("output")
- .short("o")
- .long("output")
- .help("Write Rust bindings to <output>.")
- .takes_value(true),
- Arg::with_name("raw-line")
- .long("raw-line")
- .help("Add a raw line of Rust code at the beginning of output.")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("module-raw-line")
- .long("module-raw-line")
- .help("Add a raw line of Rust code to a given module.")
- .takes_value(true)
- .multiple(true)
- .number_of_values(2)
- .value_names(&["module-name", "raw-line"]),
- Arg::with_name("rust-target")
- .long("rust-target")
- .help(&rust_target_help)
- .takes_value(true),
- Arg::with_name("use-core")
- .long("use-core")
- .help("Use types from Rust core instead of std."),
- Arg::with_name("conservative-inline-namespaces")
- .long("conservative-inline-namespaces")
- .help(
- "Conservatively generate inline namespaces to avoid name \
- conflicts.",
- ),
- Arg::with_name("use-msvc-mangling")
- .long("use-msvc-mangling")
- .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."),
- Arg::with_name("allowlist-function")
- .long("allowlist-function")
- .alias("whitelist-function")
- .help(
- "Allowlist all the free-standing functions matching \
- <regex>. Other non-allowlisted functions will not be \
- generated.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("generate-inline-functions")
- .long("generate-inline-functions")
- .help("Generate inline functions."),
- Arg::with_name("allowlist-type")
- .long("allowlist-type")
- .alias("whitelist-type")
- .help(
- "Only generate types matching <regex>. Other non-allowlisted types will \
- not be generated.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("allowlist-var")
- .long("allowlist-var")
- .alias("whitelist-var")
- .help(
- "Allowlist all the free-standing variables matching \
- <regex>. Other non-allowlisted variables will not be \
- generated.",
- )
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("verbose")
- .long("verbose")
- .help("Print verbose error messages."),
- Arg::with_name("dump-preprocessed-input")
- .long("dump-preprocessed-input")
- .help(
- "Preprocess and dump the input header files to disk. \
- Useful when debugging bindgen, using C-Reduce, or when \
- filing issues. The resulting file will be named \
- something like `__bindgen.i` or `__bindgen.ii`.",
- ),
- Arg::with_name("no-record-matches")
- .long("no-record-matches")
- .help(
- "Do not record matching items in the regex sets. \
- This disables reporting of unused items.",
- ),
- Arg::with_name("size_t-is-usize")
- .long("size_t-is-usize")
- .help("Translate size_t to usize."),
- Arg::with_name("no-rustfmt-bindings")
- .long("no-rustfmt-bindings")
- .help("Do not format the generated bindings with rustfmt."),
- Arg::with_name("rustfmt-bindings")
- .long("rustfmt-bindings")
- .help(
- "Format the generated bindings with rustfmt. DEPRECATED: \
- --rustfmt-bindings is now enabled by default. Disable \
- with --no-rustfmt-bindings.",
- ),
- Arg::with_name("rustfmt-configuration-file")
- .long("rustfmt-configuration-file")
- .help(
- "The absolute path to the rustfmt configuration file. \
- The configuration file will be used for formatting the bindings. \
- This parameter is incompatible with --no-rustfmt-bindings.",
- )
- .value_name("path")
- .takes_value(true)
- .multiple(false)
- .number_of_values(1),
- Arg::with_name("no-partialeq")
- .long("no-partialeq")
- .help("Avoid deriving PartialEq for types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("no-copy")
- .long("no-copy")
- .help("Avoid deriving Copy for types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("no-debug")
- .long("no-debug")
- .help("Avoid deriving Debug for types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("no-default")
- .long("no-default")
- .help("Avoid deriving/implement Default for types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("no-hash")
- .long("no-hash")
- .help("Avoid deriving Hash for types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("must-use-type")
- .long("must-use-type")
- .help("Add #[must_use] annotation to types matching <regex>.")
- .value_name("regex")
- .takes_value(true)
- .multiple(true)
- .number_of_values(1),
- Arg::with_name("enable-function-attribute-detection")
- .long("enable-function-attribute-detection")
- .help(
- "Enables detecting unexposed attributes in functions (slow).
- Used to generate #[must_use] annotations.",
- ),
- Arg::with_name("use-array-pointers-in-arguments")
- .long("use-array-pointers-in-arguments")
- .help("Use `*const [T; size]` instead of `*const T` for C arrays"),
- Arg::with_name("wasm-import-module-name")
- .long("wasm-import-module-name")
- .value_name("name")
- .takes_value(true)
- .help("The name to be used in a #[link(wasm_import_module = ...)] statement"),
- Arg::with_name("dynamic-loading")
- .long("dynamic-loading")
- .takes_value(true)
- .help("Use dynamic loading mode with the given library name."),
- Arg::with_name("dynamic-link-require-all")
- .long("dynamic-link-require-all")
- .help("Require successful linkage to all functions in the library."),
- Arg::with_name("respect-cxx-access-specs")
- .long("respect-cxx-access-specs")
- .help("Makes generated bindings `pub` only for items if the items are publically accessible in C++."),
- Arg::with_name("translate-enum-integer-types")
- .long("translate-enum-integer-types")
- .help("Always translate enum integer types to native Rust integer types."),
- Arg::with_name("c-naming")
- .long("c-naming")
- .help("Generate types with C style naming."),
- Arg::with_name("explicit-padding")
- .long("explicit-padding")
- .help("Always output explicit padding fields."),
- ]) // .args()
- .get_matches_from(args);
-
- let mut builder = builder();
-
- if let Some(header) = matches.value_of("header") {
- builder = builder.header(header);
- } else {
- return Err(Error::new(ErrorKind::Other, "Header not found"));
- }
-
- if matches.is_present("unstable-rust") {
- builder = builder.rust_target(RustTarget::Nightly);
- writeln!(
- &mut stderr(),
- "warning: the `--unstable-rust` option is deprecated"
- )
- .expect("Unable to write error message");
- }
-
- if let Some(rust_target) = matches.value_of("rust-target") {
- builder = builder.rust_target(RustTarget::from_str(rust_target)?);
- }
-
- if let Some(variant) = matches.value_of("default-enum-style") {
- builder = builder.default_enum_style(EnumVariation::from_str(variant)?)
- }
-
- if let Some(bitfields) = matches.values_of("bitfield-enum") {
- for regex in bitfields {
- builder = builder.bitfield_enum(regex);
- }
- }
-
- if let Some(newtypes) = matches.values_of("newtype-enum") {
- for regex in newtypes {
- builder = builder.newtype_enum(regex);
- }
- }
-
- if let Some(rustifieds) = matches.values_of("rustified-enum") {
- for regex in rustifieds {
- builder = builder.rustified_enum(regex);
- }
- }
-
- if let Some(const_enums) = matches.values_of("constified-enum") {
- for regex in const_enums {
- builder = builder.constified_enum(regex);
- }
- }
-
- if let Some(constified_mods) = matches.values_of("constified-enum-module") {
- for regex in constified_mods {
- builder = builder.constified_enum_module(regex);
- }
- }
-
- if let Some(variant) = matches.value_of("default-macro-constant-type") {
- builder = builder
- .default_macro_constant_type(MacroTypeVariation::from_str(variant)?)
- }
-
- if let Some(variant) = matches.value_of("default-alias-style") {
- builder =
- builder.default_alias_style(AliasVariation::from_str(variant)?);
- }
-
- if let Some(type_alias) = matches.values_of("normal-alias") {
- for regex in type_alias {
- builder = builder.type_alias(regex);
- }
- }
-
- if let Some(new_type) = matches.values_of("new-type-alias") {
- for regex in new_type {
- builder = builder.new_type_alias(regex);
- }
- }
-
- if let Some(new_type_deref) = matches.values_of("new-type-alias-deref") {
- for regex in new_type_deref {
- builder = builder.new_type_alias_deref(regex);
- }
- }
-
- if let Some(hidden_types) = matches.values_of("blocklist-type") {
- for ty in hidden_types {
- builder = builder.blocklist_type(ty);
- }
- }
-
- if let Some(hidden_functions) = matches.values_of("blocklist-function") {
- for fun in hidden_functions {
- builder = builder.blocklist_function(fun);
- }
- }
-
- if let Some(hidden_identifiers) = matches.values_of("blocklist-item") {
- for id in hidden_identifiers {
- builder = builder.blocklist_item(id);
- }
- }
-
- if let Some(hidden_files) = matches.values_of("blocklist-file") {
- for file in hidden_files {
- builder = builder.blocklist_file(file);
- }
- }
-
- if matches.is_present("builtins") {
- builder = builder.emit_builtins();
- }
-
- if matches.is_present("no-layout-tests") {
- builder = builder.layout_tests(false);
- }
-
- if matches.is_present("no-derive-copy") {
- builder = builder.derive_copy(false);
- }
-
- if matches.is_present("no-derive-debug") {
- builder = builder.derive_debug(false);
- }
-
- if matches.is_present("impl-debug") {
- builder = builder.impl_debug(true);
- }
-
- if matches.is_present("impl-partialeq") {
- builder = builder.impl_partialeq(true);
- }
-
- if matches.is_present("with-derive-default") {
- builder = builder.derive_default(true);
- }
-
- if matches.is_present("with-derive-hash") {
- builder = builder.derive_hash(true);
- }
-
- if matches.is_present("with-derive-partialeq") {
- builder = builder.derive_partialeq(true);
- }
-
- if matches.is_present("with-derive-partialord") {
- builder = builder.derive_partialord(true);
- }
-
- if matches.is_present("with-derive-eq") {
- builder = builder.derive_eq(true);
- }
-
- if matches.is_present("with-derive-ord") {
- builder = builder.derive_ord(true);
- }
-
- if matches.is_present("no-derive-default") {
- builder = builder.derive_default(false);
- }
-
- if matches.is_present("no-prepend-enum-name") {
- builder = builder.prepend_enum_name(false);
- }
-
- if matches.is_present("no-include-path-detection") {
- builder = builder.detect_include_paths(false);
- }
-
- if matches.is_present("fit-macro-constant-types") {
- builder = builder.fit_macro_constants(true);
- }
-
- if matches.is_present("time-phases") {
- builder = builder.time_phases(true);
- }
-
- if matches.is_present("use-array-pointers-in-arguments") {
- builder = builder.array_pointers_in_arguments(true);
- }
-
- if let Some(wasm_import_name) = matches.value_of("wasm-import-module-name")
- {
- builder = builder.wasm_import_module_name(wasm_import_name);
- }
-
- if let Some(prefix) = matches.value_of("ctypes-prefix") {
- builder = builder.ctypes_prefix(prefix);
- }
-
- if let Some(prefix) = matches.value_of("anon-fields-prefix") {
- builder = builder.anon_fields_prefix(prefix);
- }
-
- if let Some(what_to_generate) = matches.value_of("generate") {
- let mut config = CodegenConfig::empty();
- for what in what_to_generate.split(',') {
- match what {
- "functions" => config.insert(CodegenConfig::FUNCTIONS),
- "types" => config.insert(CodegenConfig::TYPES),
- "vars" => config.insert(CodegenConfig::VARS),
- "methods" => config.insert(CodegenConfig::METHODS),
- "constructors" => config.insert(CodegenConfig::CONSTRUCTORS),
- "destructors" => config.insert(CodegenConfig::DESTRUCTORS),
- otherwise => {
- return Err(Error::new(
- ErrorKind::Other,
- format!("Unknown generate item: {}", otherwise),
- ));
- }
- }
- }
- builder = builder.with_codegen_config(config);
- }
-
- if matches.is_present("emit-clang-ast") {
- builder = builder.emit_clang_ast();
- }
-
- if matches.is_present("emit-ir") {
- builder = builder.emit_ir();
- }
-
- if let Some(path) = matches.value_of("emit-ir-graphviz") {
- builder = builder.emit_ir_graphviz(path);
- }
-
- if matches.is_present("enable-cxx-namespaces") {
- builder = builder.enable_cxx_namespaces();
- }
-
- if matches.is_present("enable-function-attribute-detection") {
- builder = builder.enable_function_attribute_detection();
- }
-
- if matches.is_present("disable-name-namespacing") {
- builder = builder.disable_name_namespacing();
- }
-
- if matches.is_present("disable-nested-struct-naming") {
- builder = builder.disable_nested_struct_naming();
- }
-
- if matches.is_present("disable-untagged-union") {
- builder = builder.disable_untagged_union();
- }
-
- if matches.is_present("disable-header-comment") {
- builder = builder.disable_header_comment();
- }
-
- if matches.is_present("ignore-functions") {
- builder = builder.ignore_functions();
- }
-
- if matches.is_present("ignore-methods") {
- builder = builder.ignore_methods();
- }
-
- if matches.is_present("no-convert-floats") {
- builder = builder.no_convert_floats();
- }
-
- if matches.is_present("no-doc-comments") {
- builder = builder.generate_comments(false);
- }
-
- if matches.is_present("no-recursive-allowlist") {
- builder = builder.allowlist_recursively(false);
- }
-
- if matches.is_present("objc-extern-crate") {
- builder = builder.objc_extern_crate(true);
- }
-
- if matches.is_present("generate-block") {
- builder = builder.generate_block(true);
- }
-
- if matches.is_present("block-extern-crate") {
- builder = builder.block_extern_crate(true);
- }
-
- if let Some(opaque_types) = matches.values_of("opaque-type") {
- for ty in opaque_types {
- builder = builder.opaque_type(ty);
- }
- }
-
- if let Some(lines) = matches.values_of("raw-line") {
- for line in lines {
- builder = builder.raw_line(line);
- }
- }
-
- if let Some(mut values) = matches.values_of("module-raw-line") {
- while let Some(module) = values.next() {
- let line = values.next().unwrap();
- builder = builder.module_raw_line(module, line);
- }
- }
-
- if matches.is_present("use-core") {
- builder = builder.use_core();
- }
-
- if matches.is_present("distrust-clang-mangling") {
- builder = builder.trust_clang_mangling(false);
- }
-
- if matches.is_present("conservative-inline-namespaces") {
- builder = builder.conservative_inline_namespaces();
- }
-
- if matches.is_present("generate-inline-functions") {
- builder = builder.generate_inline_functions(true);
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-function") {
- for regex in allowlist {
- builder = builder.allowlist_function(regex);
- }
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-type") {
- for regex in allowlist {
- builder = builder.allowlist_type(regex);
- }
- }
-
- if let Some(allowlist) = matches.values_of("allowlist-var") {
- for regex in allowlist {
- builder = builder.allowlist_var(regex);
- }
- }
-
- if let Some(args) = matches.values_of("clang-args") {
- for arg in args {
- builder = builder.clang_arg(arg);
- }
- }
-
- let output = if let Some(path) = matches.value_of("output") {
- let file = File::create(path)?;
- if let Some(depfile) = matches.value_of("depfile") {
- builder = builder.depfile(path, depfile);
- }
- Box::new(io::BufWriter::new(file)) as Box<dyn io::Write>
- } else {
- if let Some(depfile) = matches.value_of("depfile") {
- builder = builder.depfile("-", depfile);
- }
- Box::new(io::BufWriter::new(io::stdout())) as Box<dyn io::Write>
- };
-
- if matches.is_present("dump-preprocessed-input") {
- builder.dump_preprocessed_input()?;
- }
-
- if matches.is_present("no-record-matches") {
- builder = builder.record_matches(false);
- }
-
- if matches.is_present("size_t-is-usize") {
- builder = builder.size_t_is_usize(true);
- }
-
- let no_rustfmt_bindings = matches.is_present("no-rustfmt-bindings");
- if no_rustfmt_bindings {
- builder = builder.rustfmt_bindings(false);
- }
-
- if let Some(path_str) = matches.value_of("rustfmt-configuration-file") {
- let path = PathBuf::from(path_str);
-
- if no_rustfmt_bindings {
- return Err(Error::new(
- ErrorKind::Other,
- "Cannot supply both --rustfmt-configuration-file and --no-rustfmt-bindings",
- ));
- }
-
- if !path.is_absolute() {
- return Err(Error::new(
- ErrorKind::Other,
- "--rustfmt-configuration--file needs to be an absolute path!",
- ));
- }
-
- if path.to_str().is_none() {
- return Err(Error::new(
- ErrorKind::Other,
- "--rustfmt-configuration-file contains non-valid UTF8 characters.",
- ));
- }
-
- builder = builder.rustfmt_configuration_file(Some(path));
- }
-
- if let Some(no_partialeq) = matches.values_of("no-partialeq") {
- for regex in no_partialeq {
- builder = builder.no_partialeq(regex);
- }
- }
-
- if let Some(no_copy) = matches.values_of("no-copy") {
- for regex in no_copy {
- builder = builder.no_copy(regex);
- }
- }
-
- if let Some(no_debug) = matches.values_of("no-debug") {
- for regex in no_debug {
- builder = builder.no_debug(regex);
- }
- }
-
- if let Some(no_default) = matches.values_of("no-default") {
- for regex in no_default {
- builder = builder.no_default(regex);
- }
- }
-
- if let Some(no_hash) = matches.values_of("no-hash") {
- for regex in no_hash {
- builder = builder.no_hash(regex);
- }
- }
-
- if let Some(must_use_type) = matches.values_of("must-use-type") {
- for regex in must_use_type {
- builder = builder.must_use_type(regex);
- }
- }
-
- if let Some(dynamic_library_name) = matches.value_of("dynamic-loading") {
- builder = builder.dynamic_library_name(dynamic_library_name);
- }
-
- if matches.is_present("dynamic-link-require-all") {
- builder = builder.dynamic_link_require_all(true);
- }
-
- if matches.is_present("respect-cxx-access-specs") {
- builder = builder.respect_cxx_access_specs(true);
- }
-
- if matches.is_present("translate-enum-integer-types") {
- builder = builder.translate_enum_integer_types(true);
- }
-
- if matches.is_present("c-naming") {
- builder = builder.c_naming(true);
- }
-
- if matches.is_present("explicit-padding") {
- builder = builder.explicit_padding(true);
- }
-
- let verbose = matches.is_present("verbose");
-
- Ok((builder, output, verbose))
-}
diff --git a/src/parse.rs b/src/parse.rs
deleted file mode 100644
index f60de43..0000000
--- a/src/parse.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! Common traits and types related to parsing our IR from Clang cursors.
-
-use crate::clang;
-use crate::ir::context::{BindgenContext, ItemId, TypeId};
-use crate::ir::ty::TypeKind;
-
-/// Not so much an error in the traditional sense, but a control flow message
-/// when walking over Clang's AST with a cursor.
-#[derive(Debug)]
-pub enum ParseError {
- /// Recurse down the current AST node's children.
- Recurse,
- /// Continue on to the next sibling AST node, or back up to the parent's
- /// siblings if we've exhausted all of this node's siblings (and so on).
- Continue,
-}
-
-/// The result of parsing a Clang AST node.
-#[derive(Debug)]
-pub enum ParseResult<T> {
- /// We've already resolved this item before, here is the extant `ItemId` for
- /// it.
- AlreadyResolved(ItemId),
-
- /// This is a newly parsed item. If the cursor is `Some`, it points to the
- /// AST node where the new `T` was declared.
- New(T, Option<clang::Cursor>),
-}
-
-/// An intermediate representation "sub-item" (i.e. one of the types contained
-/// inside an `ItemKind` variant) that can be parsed from a Clang cursor.
-pub trait ClangSubItemParser: Sized {
- /// Attempt to parse this type from the given cursor.
- ///
- /// The fact that is a reference guarantees it's held by the context, and
- /// allow returning already existing types.
- fn parse(
- cursor: clang::Cursor,
- context: &mut BindgenContext,
- ) -> Result<ParseResult<Self>, ParseError>;
-}
-
-/// An intermediate representation item that can be parsed from a Clang cursor.
-pub trait ClangItemParser: Sized {
- /// Parse this item from the given Clang cursor.
- fn parse(
- cursor: clang::Cursor,
- parent: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> Result<ItemId, ParseError>;
-
- /// Parse this item from the given Clang type.
- fn from_ty(
- ty: &clang::Type,
- location: clang::Cursor,
- parent: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError>;
-
- /// Identical to `from_ty`, but use the given `id` as the `ItemId` for the
- /// newly parsed item.
- fn from_ty_with_id(
- id: ItemId,
- ty: &clang::Type,
- location: clang::Cursor,
- parent: Option<ItemId>,
- ctx: &mut BindgenContext,
- ) -> Result<TypeId, ParseError>;
-
- /// Parse this item from the given Clang type, or if we haven't resolved all
- /// the other items this one depends on, an unresolved reference.
- fn from_ty_or_ref(
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> TypeId;
-
- /// Identical to `from_ty_or_ref`, but use the given `potential_id` as the
- /// `ItemId` for the newly parsed item.
- fn from_ty_or_ref_with_id(
- potential_id: ItemId,
- ty: clang::Type,
- location: clang::Cursor,
- parent_id: Option<ItemId>,
- context: &mut BindgenContext,
- ) -> TypeId;
-
- /// Create a named template type.
- fn type_param(
- with_id: Option<ItemId>,
- location: clang::Cursor,
- ctx: &mut BindgenContext,
- ) -> Option<TypeId>;
-
- /// Create a builtin type.
- fn builtin_type(
- kind: TypeKind,
- is_const: bool,
- context: &mut BindgenContext,
- ) -> TypeId;
-}
diff --git a/src/time.rs b/time.rs
index c13a640..c13a640 100644
--- a/src/time.rs
+++ b/time.rs