Binary files firefox-140.10.2.orig/.cargo/.global-cache and firefox-140.10.2/.cargo/.global-cache differ diff -rNu firefox-140.10.2.orig/.cargo/config.toml.in firefox-140.10.2/.cargo/config.toml.in --- firefox-140.10.2.orig/.cargo/config.toml.in Wed May 6 16:54:36 2026 +++ firefox-140.10.2/.cargo/config.toml.in Mon May 11 04:50:32 2026 @@ -110,6 +110,11 @@ tag = "v0.13.4" replace-with = "vendored-sources" +[source."git+https://github.com/rust-lang/rust-bindgen?rev=9366e0af8da529c958b4cd4fcbe492d951c86f5c"] +git = "https://github.com/rust-lang/rust-bindgen" +rev = "9366e0af8da529c958b4cd4fcbe492d951c86f5c" +replace-with = "vendored-sources" + [source."git+https://github.com/servo/rust-cssparser?rev=958a3f098acb92ddacdce18a7ef2c4a87ac3326f"] git = "https://github.com/servo/rust-cssparser" rev = "958a3f098acb92ddacdce18a7ef2c4a87ac3326f" diff -rNu firefox-140.10.2.orig/Cargo.lock firefox-140.10.2/Cargo.lock --- firefox-140.10.2.orig/Cargo.lock Wed May 6 16:54:36 2026 +++ firefox-140.10.2/Cargo.lock Mon May 11 07:16:53 2026 @@ -454,25 +454,24 @@ [[package]] name = "bindgen" -version = "0.64.999" +version = "0.69.999" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.72.0", ] [[package]] name = "bindgen" -version = "0.69.4" +version = "0.72.0" +source = "git+https://github.com/rust-lang/rust-bindgen?rev=9366e0af8da529c958b4cd4fcbe492d951c86f5c#9366e0af8da529c958b4cd4fcbe492d951c86f5c" dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.10.999", - "lazy_static", - "lazycell", + "itertools 0.14.0", "proc-macro2", "quote", "regex", - "rustc-hash 1.999.999", + "rustc-hash 2.1.1", "shlex", "syn", ] @@ -947,7 +946,7 @@ name = "cocoabind" version = "0.1.0" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "block", "mozbuild", "objc", @@ -1080,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3120ebb80a9de008e638ad833d4127d50ea3d3a960ea23ea69bc66d9358a028" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", ] [[package]] @@ -1208,7 +1207,7 @@ version = "1.0.0" dependencies = [ "anyhow", - "bindgen 0.69.4", + "bindgen 0.69.999", "block", "buildid_reader", "bytes", @@ -2395,7 +2394,7 @@ version = "0.1.0" dependencies = [ "bincode", - "bindgen 0.69.4", + "bindgen 0.69.999", "lazy_static", "mozbuild", "profiler-macros", @@ -2878,7 +2877,7 @@ name = "gtkbind" version = "0.1.0" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "mozbuild", ] @@ -3041,7 +3040,7 @@ version = "0.1.1" dependencies = [ "base64 0.22.1", - "bindgen 0.69.4", + "bindgen 0.69.999", "cfg-if", "http", "hyper", @@ -3666,12 +3665,6 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] name = "leak" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4469,7 +4462,7 @@ dependencies = [ "allocator-api2", "arrayvec", - "bindgen 0.69.4", + "bindgen 0.69.999", "bitflags 2.9.0", "byteorder", "bytes", @@ -4639,7 +4632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c30d3771729ec4349aae3b1a7c0b6b4a1500459e60b1fda95fe0657c3711574" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "cfg_aliases", "libc", "mozbuild", @@ -4705,7 +4698,6 @@ [[package]] name = "neqo-common" version = "0.13.4" -source = "git+https://github.com/mozilla/neqo?tag=v0.13.4#c3179d9f363bf92a908d90e4240b315b9ff72516" dependencies = [ "enum-map", "env_logger", @@ -4718,9 +4710,8 @@ [[package]] name = "neqo-crypto" version = "0.13.4" -source = "git+https://github.com/mozilla/neqo?tag=v0.13.4#c3179d9f363bf92a908d90e4240b315b9ff72516" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "enum-map", "log", "mozbuild", @@ -4892,7 +4883,7 @@ version = "0.3.0" source = "git+https://github.com/beurdouche/nss-gk-api?rev=e48a946811ffd64abc78de3ee284957d8d1c0d63#e48a946811ffd64abc78de3ee284957d8d1c0d63" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.72.0", "log", "mozbuild", "once_cell", @@ -4998,7 +4989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578cb11a3fb5c85697ed8bb850d5ad1cbf819d3eea05c2b253cf1d240fbb10c5" dependencies = [ - "bindgen 0.64.999", + "bindgen 0.69.999", "byteorder", "hex", "lazy_static", @@ -5251,7 +5242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0fabbdbe64b22820753da90995b3a73d02907eaeeac6f2414962a566aaa18ea" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.72.0", ] [[package]] @@ -6344,7 +6335,7 @@ "app_units", "arrayvec", "atomic_refcell", - "bindgen 0.69.4", + "bindgen 0.69.999", "bitflags 2.9.0", "byteorder", "cssparser", @@ -6594,7 +6585,7 @@ name = "test-trust-anchors-static" version = "0.1.0" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "mozbuild", "mozilla-central-workspace-hack", "nom", @@ -6864,7 +6855,7 @@ name = "trust-anchors" version = "0.1.0" dependencies = [ - "bindgen 0.69.4", + "bindgen 0.69.999", "mozbuild", "nom", "pkcs11-bindings", diff -rNu firefox-140.10.2.orig/Cargo.toml firefox-140.10.2/Cargo.toml --- firefox-140.10.2.orig/Cargo.toml Wed May 6 16:54:36 2026 +++ firefox-140.10.2/Cargo.toml Mon May 11 05:33:36 2026 @@ -160,12 +160,12 @@ # else we do use requires backtrace, so dummy it out for now. backtrace = { path = "build/rust/backtrace" } -# Patch bindgen 0.63 to 0.69 -bindgen_0_63 = { package = "bindgen", path = "build/rust/bindgen-0.63" } -# Locally patch bindgen for https://github.com/rust-lang/rust-bindgen/pull/2824 -# and for bug 1945218 -bindgen = { path = "third_party/rust/bindgen" } +# Locally patch bindgen to a yet-unreleased version. +bindgen_0_72 = { package = "bindgen", git = "https://github.com/rust-lang/rust-bindgen", rev = "9366e0af8da529c958b4cd4fcbe492d951c86f5c" } +# Patch bindgen 0.69 to 0.72 +bindgen = { path = "build/rust/bindgen" } + # Patch nix 0.26 to 0.30+ nix_0_26 = { package = "nix", path = "build/rust/nix" } @@ -266,6 +266,12 @@ # allocator-api2 + f95e3419ce41883904fcb2279b52aa35b5f04d76 + fdd92751afa7ce34408b677004b429d597e72c90 allocator-api2 = { git = "https://github.com/glandium/allocator-api2", rev = "ad5f3d56a5a4519eff52af4ff85293431466ef5c" } + +# Patch neqo-crypto (and neqo-common to avoid duplicating it) to cherry-pick +# https://github.com/mozilla/neqo/pull/2913 +[patch."https://github.com/mozilla/neqo"] +neqo-crypto = { path = "third_party/rust/neqo-crypto" } +neqo-common = { path = "third_party/rust/neqo-common" } # application-services overrides to make updating them all simpler. context_id = { git = "https://github.com/mozilla/application-services", rev = "f5907a411e52a3985d0369d71c486eb507c2c4e6" } diff -rNu firefox-140.10.2.orig/build/rust/bindgen/Cargo.toml firefox-140.10.2/build/rust/bindgen/Cargo.toml --- firefox-140.10.2.orig/build/rust/bindgen/Cargo.toml Thu Jan 1 01:00:00 1970 +++ firefox-140.10.2/build/rust/bindgen/Cargo.toml Mon May 11 05:33:19 2026 @@ -0,0 +1,18 @@ +[package] +name = "bindgen" +version = "0.69.999" +edition = "2018" +license = "MPL-2.0" + +[lib] +path = "lib.rs" + +[dependencies.bindgen] +version = "0.72.0" +default-features = false + +[features] +logging = ["bindgen/logging"] +runtime = ["bindgen/runtime"] +static = ["bindgen/static"] +which-rustfmt = ["bindgen/which-rustfmt"] diff -rNu firefox-140.10.2.orig/build/rust/bindgen/lib.rs firefox-140.10.2/build/rust/bindgen/lib.rs --- firefox-140.10.2.orig/build/rust/bindgen/lib.rs Thu Jan 1 01:00:00 1970 +++ firefox-140.10.2/build/rust/bindgen/lib.rs Mon May 11 04:49:32 2026 @@ -0,0 +1,5 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +pub use bindgen::*; diff -rNu firefox-140.10.2.orig/layout/style/ServoBindings.toml firefox-140.10.2/layout/style/ServoBindings.toml --- firefox-140.10.2.orig/layout/style/ServoBindings.toml Wed May 6 16:54:43 2026 +++ firefox-140.10.2/layout/style/ServoBindings.toml Mon May 11 04:51:28 2026 @@ -297,8 +297,10 @@ "std::atomic", "std::.*::atomic", "std::atomic___base", + "std::function", "std::tuple.*", # Causes "Cannot find type _Pred in this scope" error on mac, like rust-skia#571 "std::.*::tuple.*", + "mozilla::dom::FrameRequestManager", "mozilla::dom::Touch", "mozilla::dom::Sequence", diff -rNu firefox-140.10.2.orig/servo/components/style/gecko/snapshot_helpers.rs firefox-140.10.2/servo/components/style/gecko/snapshot_helpers.rs --- firefox-140.10.2.orig/servo/components/style/gecko/snapshot_helpers.rs Wed May 6 16:54:45 2026 +++ firefox-140.10.2/servo/components/style/gecko/snapshot_helpers.rs Mon May 11 04:49:32 2026 @@ -58,7 +58,7 @@ .mAtomArray .as_ref(); let array = - (*attr_array).mArray.as_ptr() as *const structs::nsTArray>; + (*attr_array).mArray.0.as_ptr() as *const structs::nsTArray>; return Class::More(&**array); } debug_assert_eq!(base_type, structs::nsAttrValue_ValueBaseType_eStringBase); diff -rNu firefox-140.10.2.orig/supply-chain/audits.toml firefox-140.10.2/supply-chain/audits.toml --- firefox-140.10.2.orig/supply-chain/audits.toml Wed May 6 16:54:45 2026 +++ firefox-140.10.2/supply-chain/audits.toml Mon May 11 04:49:32 2026 @@ -1028,6 +1028,19 @@ criteria = "safe-to-deploy" delta = "0.69.2 -> 0.69.4" +[[audits.bindgen]] +who = "Emilio Cobos Álvarez " +criteria = "safe-to-deploy" +delta = "0.69.4 -> 0.72.0" +notes = "I'm the primary maintainer of this crate." + +[[audits.bindgen]] +who = "Emilio Cobos Álvarez " +criteria = "safe-to-deploy" +delta = "0.72.0 -> 0.72.0@git:9366e0af8da529c958b4cd4fcbe492d951c86f5c" +importable = false +notes = "Authored or reviewed all relevant changes upstream." + [[audits.bit-set]] who = "Aria Beingessner " criteria = "safe-to-deploy" diff -rNu firefox-140.10.2.orig/supply-chain/config.toml firefox-140.10.2/supply-chain/config.toml --- firefox-140.10.2.orig/supply-chain/config.toml Wed May 6 16:54:45 2026 +++ firefox-140.10.2/supply-chain/config.toml Mon May 11 04:49:32 2026 @@ -31,9 +31,9 @@ audit-as-crates-io = true notes = "This is the upstream code plus a few local fixes, see bug 1685697." -[policy."bindgen:0.69.4"] +[policy."bindgen:0.72.0@git:9366e0af8da529c958b4cd4fcbe492d951c86f5c"] audit-as-crates-io = true -notes = "This is the upstream code plus a fix for clang trunk. See bug 1894093." +notes = "This is the upstream code not yet released" [policy.chardetng] audit-as-crates-io = true diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/.cargo-checksum.json firefox-140.10.2/third_party/rust/bindgen/.cargo-checksum.json --- firefox-140.10.2.orig/third_party/rust/bindgen/.cargo-checksum.json Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/.cargo-checksum.json Mon May 11 04:49:32 2026 @@ -1 +1 @@ -{"files":{"Cargo.toml":"bebb685bfd8df63474c92bfb7f787573ef78eb70920aceb38a8a746968380f96","LICENSE":"c23953d9deb0a3312dbeaf6c128a657f3591acee45067612fa68405eaa4525db","README.md":"b2334e4077a9bc329516e3e0c7f89887c4f073647d95fb71b6917edf4c310ba3","build.rs":"4a9c4ac3759572e17de312a9d3f4ced3b6fd3c71811729e5a8d06bfbd1ac8f82","callbacks.rs":"cd5a1b0fc665b034d97615d0b6817cbef299dbf5276254c7e63f1c29674993ad","clang.rs":"278ca0d89251df8a6b40bdccd27827e310d16872ff86fa23b60d581615607630","codegen/bitfield_unit.rs":"fddeaeab5859f4e82081865595b7705f5c0774d997df95fa5c655b81b9cae125","codegen/bitfield_unit_tests.rs":"9df86490de5e9d66ccea583dcb686dd440375dc1a3c3cf89a89d5de3883bf28a","codegen/dyngen.rs":"6d8bed53c6de66bc658b3186041c2b75549f49b0f0363ff18b87c8dcf2f5a05b","codegen/error.rs":"0c3d198f4866ccbbcd8b1136fc5cfd2507a9eca5ab85934af29a7e2a7d8d8c2a","codegen/helpers.rs":"443a2c3495185ced2a9d68c02204bebfa8c4186f4275bf9ed3af90c3a3e159d7","codegen/impl_debug.rs":"80df6136327b1ca8c7d1c2961290b5ab00b85b49b22c02f26a590bc68fb230af","codegen/impl_partialeq.rs":"db739d7ba6f5ba4033d6bf62c276f35217c20eab27230cf07dadf59e8b2f71bb","codegen/mod.rs":"206e4e2c14cec17c13d11e568557332b51ce1e41ce8128182de44dab69221662","codegen/postprocessing/merge_extern_blocks.rs":"284457a3c75e945217bab4e5a4280fef0fcc03c31e12cc5010aab87f34c0b6c7","codegen/postprocessing/mod.rs":"160a6d6701cabf2514e23570df1bd1b648c909cc27b7c583f21d98fe0c16722e","codegen/postprocessing/sort_semantically.rs":"f465d1e8cc119082eb79c164b5cd780a370821e8bf56585b287dd3b51fc4a542","codegen/serialize.rs":"1f1eb8b04fec9655dc302442451f9622ad6365eb37bf588a119a60e79f37002c","codegen/struct_layout.rs":"922cc71fb309716879aeea4775bbc29751ca5d431083ca83d7beb0a90862a302","deps.rs":"af3dd24a7808b5abf0c4ed4b10bbceb8eef32be980ff085b8a766d8f089af1a4","diagnostics.rs":"dc40cd5e9710922422c5c9420e2351f5d976e7a1d7275e4f4ce742cad9eb53f8","extra_assertions.rs":"fb4484c0e9fcbea9ec7265f5fbd01e2b33ac022b2b17e060dce7886819d57e40","features.rs":"b27adc6bb50e9aae50fd75568a7576382c6409f585b6be0047d7a9314c98d569","ir/analysis/derive.rs":"cba290e9c4ba271e90524149ad3b874f37843bfdfab12d513cc85d2665447fd5","ir/analysis/has_destructor.rs":"e7e95c3b0989b6375cd3eabaac85a36ecc2915a1fd3700c7d26fe04e8dc83ba3","ir/analysis/has_float.rs":"a56b97bf913f132c2c63dc202b45c692c416a8c9fdc6b2baeee30362fb0d4405","ir/analysis/has_type_param_in_array.rs":"788ebb4ba2cf46a22f1e4ff3005d51f38d414b72e95355f7ff4125521e2d9525","ir/analysis/has_vtable.rs":"83efa40ae89147170eabdff1387e60aba574ca4cd4cdef22692753594f09d6c6","ir/analysis/mod.rs":"9d949c27451da4ed72994b31c04ddeb89eeb342fd23ea572d3962d4ccf774841","ir/analysis/sizedness.rs":"f0a9302f3c6ad694d76cfab11dbaf5392ecaf7f04bc7b211a5a003776b963896","ir/analysis/template_params.rs":"3ff27e2198e292a348876aa1faba39cc4b1870a24a7e173feac0b3c592001e13","ir/annotations.rs":"5ed03d025862d0d21852a76c86a993772624e123fdc3752415d588a0b4e643ab","ir/comment.rs":"4c9c20b5a3da086211e92adec0822831dbc0b7ebee98fee313edcae9ae8d55ec","ir/comp.rs":"c048866353695ac8190ab03511123be82d34ca73fb865a2578cb5a2e04390431","ir/context.rs":"03175218512c42792aae7b56a764c0237a447664dda5f1a8269a42bed46d3be2","ir/derive.rs":"c21e470bb0091f20bfa366110880d48984fc3cf7071fdf36eccfa64f3eca231c","ir/dot.rs":"75bdfd83d9e754ba726f6a5529ba1d9ff46f5bf49bf237452985eb008fed0854","ir/enum_ty.rs":"f4bfa6d18ba4977fb66f5d5e4a7674eded93b761404d91cdd6fdd50029db455a","ir/function.rs":"0ecee923382b0a49265bc970ac90a73740ec5ba3c33466b2cfe8aa462df59bd5","ir/int.rs":"601736f0ad0949e40684a9ce89bafbfefa71743df6ee6c342e44888a0f141ae0","ir/item.rs":"65f2351dd3971d8a76470a78f5b6b1ebdda067ab5bae4641246aa986d9579e29","ir/item_kind.rs":"33e21104b0bb824a696a52cd520567ae56158010a1df14777e68ac5f8ad7e8fa","ir/layout.rs":"8fbafc0eeee17abb703a18613be1066e38838d4b67f5916f714bf545e545bc1a","ir/mod.rs":"a3b98b1732111a980a795c72eaf1e09101e842ef2de76b4f2d4a7857f8d4cee4","ir/module.rs":"b2961ffa4acb0c19f084c5db084b8a17bda7158066782a73b80ee7d838789bf9","ir/objc.rs":"8f57a9180d57a690449f20ed1be80209db5f8a410bb067ae8bf5e0ecab16a5e4","ir/template.rs":"3f59efa9670ca90215d4374be869c9dbecb98a8d1041e7c6e4ab69a62bb982c2","ir/traversal.rs":"a4ec73d3533d4b93386153baf6a2ca846ee51228c76ed51105229d3ddcd74466","ir/ty.rs":"fd71d11e89e085921317349e1912ab56e7335d870c2d25df9e13a8ffbd6430c9","ir/var.rs":"40d18226706de0ee5f002d0b5617dbcba35de0605edd531c75e3a76d000f0f4f","lib.rs":"7496f72a177b5965ed56a2ab9af0f64e70abbc53cc6c196a15e6760dd6235adf","log_stubs.rs":"9f974e041e35c8c7e29985d27ae5cd0858d68f8676d1dc005c6388d7d011707f","options/as_args.rs":"76efa4e662cc7f89ef1c1fe089d03a3c1c019ffe2aa0a30a4d49ed41e987d1c7","options/helpers.rs":"f4a7681e29b2dcc3be9249478c499d685b9e29d4f4ca4ae8bff7a91668cd8f15","options/mod.rs":"1805cec86c563633b29b57292287c9efd3b5c724132ec1c13acee57858942e74","parse.rs":"fce3616e0464aa7414888e5d00d4df18c83bb3034a1c807d36a07a3c586e475a","regex_set.rs":"b411d64bc803947a3f69dcedcd7d03716aacbc7b1c5148b82de1cc469d9336d9","time.rs":"8efe317e7c6b5ba8e0865ce7b49ca775ee8a02590f4241ef62f647fa3c22b68e"},"package":"a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"} \ No newline at end of file +{"files":{"Cargo.toml":"a07e277ca0e2a5c37caed762a150075a651ed56a7c0a32b38f32669d2ac7c5d3","LICENSE":"c23953d9deb0a3312dbeaf6c128a657f3591acee45067612fa68405eaa4525db","build.rs":"f7a10af0a21662e104e0058da7e3471a20be328eef6c7c41988525be90fdfe92","callbacks.rs":"3f0ed344a4d27fc8f893f21b1f9cd742d85ccbc23441d745e8a147b6072469bd","clang.rs":"e991300ce9b1f0b9fb4a0b4bd32e899b6cfa546f034858f08bf57678b3d7044c","codegen/bitfield_unit.rs":"1d598b042a9ce6c2f8a2c6eb44c9ee6e2d41865f25fe34ce747a0376c4d9b951","codegen/bitfield_unit_tests.rs":"9915cb19bf37fc1013fc72753bae153f7c249280daec94b25fb461f9936dffa4","codegen/dyngen.rs":"1b42f7fa9fb65ff2fa898b289a3b934d7b21c5ba6c1b3e37aa97f0faa87769a0","codegen/error.rs":"67680c4d171d63848d9eb4ddd5f100be7463564e8c1c9203fefc0e61a19dfdec","codegen/helpers.rs":"9bcec3163826edc9b22256c9bf33dd2964809349b801fc6fa5e9158da4eb0458","codegen/impl_debug.rs":"3e55b361aa56d9b6ef2bdb96ede983385a3b1030aa0f46235cb4d218ad66b2a1","codegen/impl_partialeq.rs":"d4fb2ef354086c3dd5a4c4b69d5deab652fdef225725e28dc694e791c1573d0c","codegen/mod.rs":"b106576fce6df7a3933eaa112d805d42653c2d1287953a002a3bb70b38715f87","codegen/postprocessing/merge_extern_blocks.rs":"3e244fe62abcadcb6dae069c37d21220f5351dc7b8c33c5576a5193731933c4c","codegen/postprocessing/mod.rs":"160a6d6701cabf2514e23570df1bd1b648c909cc27b7c583f21d98fe0c16722e","codegen/postprocessing/sort_semantically.rs":"5099e8fc134a92cb72b585bd95854a52ff81e2f5307c3b83617d83e7408302ee","codegen/serialize.rs":"d57eb31ba0fda825241f886336279573050b396e52badf3886e0bc76a15110ad","codegen/struct_layout.rs":"b5f4a010d60586e5079284f7f02af53d961f02a8e6a2cf09dfab2127f20c3734","deps.rs":"297dcc2be53af1a3ea4f77e16902a641f3e6f0baad09c06a6ea26050a0281c18","diagnostics.rs":"9c80043ac9fa8f683019577f311853a0d5929e41a95b3255736f80105914cdfa","extra_assertions.rs":"1596b7e7f031714dc699ebda135e795f1ecfc971ce9de6861a3c00e77fcef011","features.rs":"cde8d530d03c2793cbbb257db3d64e345af26731b73f45b4b60a618d062443c3","ir/analysis/derive.rs":"42ef56b1adda1b4d2797c7845b909fde8c87e2bf51920b490b7129936d5c494c","ir/analysis/has_destructor.rs":"d75be0d349e744ef198d89f04274cc024e36eb255fe7fb7b660ce805c8977bae","ir/analysis/has_float.rs":"9fb88d05c5920e9000e5cb6e87775c0d1042a6b11205577e281ba281e6e6acdb","ir/analysis/has_type_param_in_array.rs":"0975d1ce43bcba97eb303635118e74d494d46ac67cf5ee53faf6f6584a556cef","ir/analysis/has_vtable.rs":"dcaf36d4d0148db3b5690166e32853a58eda7721c9ea5217723a5dba7d5295b8","ir/analysis/mod.rs":"93edca96d765dfa19ac231198027b0ba48c623502a8be1dbf799a241cd6b304b","ir/analysis/sizedness.rs":"0b78e70737e038ebdee2c3d195194a060c9287000b9059ded0686728a89b4ff2","ir/analysis/template_params.rs":"a8dfd3e02b1745a5b7c6faa16309bd0b8a88d76b7fedca27c322782cc9e77177","ir/annotations.rs":"8397ced62808fe99dfdde35792cd8b2389e7828d752a6c8aa3a70c1e14595e11","ir/comment.rs":"57863204d329ae82872ecc4829cc299969ff07da3a32a4a13d7d84429f55b84d","ir/comp.rs":"8df9d537b17994f85b3d506658c20b080d18b805ca8b73cc7af15f4d5397e8ef","ir/context.rs":"e9e1ed78f2258ff2556688d658ebf422308732924683c7860853f1c38a607066","ir/derive.rs":"09860cffec0ebecce31da0c6c9ea0cf9a0d4784262ff4eb16ea459c0d0782ac9","ir/dot.rs":"8b8f6dd13e662fcb4114949025cb43467b34fa4998a3371c101db5dd82688f44","ir/enum_ty.rs":"5d7ae2e3de172d9812425e8cc6e30d559b0743620b3b09f7d72f3b05a7e1ce98","ir/function.rs":"94bdc59bc39e043825d6cbbf5a461329462f0eb74c4c216002e1da86bf93e46b","ir/int.rs":"1bf1e4d87eca13ee2fc38ff4d56c266f303f188796f5c0d290f53162798d2d01","ir/item.rs":"6983232b2362f4d23261754f0ef242162ce66bbe9398a7707a88cb7bcee0f0fd","ir/item_kind.rs":"799fab994b5ed35045786a68003c2c12b6601cf3b07e8ccc0b9acd6f921217e0","ir/layout.rs":"7a7173efde2a9daed8562d657bad563922f798e44055e35899dd47badd46c52d","ir/mod.rs":"a3b98b1732111a980a795c72eaf1e09101e842ef2de76b4f2d4a7857f8d4cee4","ir/module.rs":"617867617ebd7e56157a9ba057441ce11a33c25138a1da64646f44ccaae7c762","ir/objc.rs":"092c7f32cec4191aa6235e4554420ab2053e0c7fec5ece016a7ed303763e8547","ir/template.rs":"1114c0924323f8b30bb32dbb3f6730dd7f5bc1f0771ad5099738e8e57111c07d","ir/traversal.rs":"3ebde94ead0fe69d51541ab61d700c7c1f6382574e4c110b8c7fe3e2c6218f19","ir/ty.rs":"6965a7678927a51c76c590aeb1d780412ad9f8cd4d11ea37e56e0a9669e5b06a","ir/var.rs":"2a94decd3adfdccd3bd0015b460d180838e3c92b122b632eed44032b80cad120","lib.rs":"805f7d4547f4e9e3ab024e98e39c6c3c2b74f2fd6cdd657915a5d0bbd7655dab","log_stubs.rs":"a636d59af2fd3745c2e416e1ab8a1e1a3888ea84cd4657a321ce22f15e0c5a87","options/as_args.rs":"a1a5e7f0dde82590371fc1a9ea5fde7f3e2252530ca74d98bb49a8ce06cc864f","options/cli.rs":"7712b6d4d3f8f4dc9a07e5e0fe21687b05c118e70e9c1952a2eebc34da20c2c4","options/helpers.rs":"f4a7681e29b2dcc3be9249478c499d685b9e29d4f4ca4ae8bff7a91668cd8f15","options/mod.rs":"2bedfdd6aa9817bdc8155ca8290e0d6055ef6d7a90353d6cb99ddc6121609693","parse.rs":"fce3616e0464aa7414888e5d00d4df18c83bb3034a1c807d36a07a3c586e475a","regex_set.rs":"d8995adb9e5cecc2d738e662a62d5081150bf967cb67e1206070e22b7265578a","time.rs":"1429af446b2b38c70ceec82c4202d4822c618cad47ba502dce72dbdc4cbb425e"},"package":null} \ No newline at end of file diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/Cargo.toml firefox-140.10.2/third_party/rust/bindgen/Cargo.toml --- firefox-140.10.2.orig/third_party/rust/bindgen/Cargo.toml Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/Cargo.toml Mon May 11 04:49:32 2026 @@ -10,10 +10,10 @@ # See Cargo.toml.orig for the original contents. [package] -edition = "2018" -rust-version = "1.60.0" +edition = "2021" +rust-version = "1.70.0" name = "bindgen" -version = "0.69.4" +version = "0.72.0" authors = [ "Jyun-Yan You ", "Emilio Cobos Álvarez ", @@ -21,10 +21,15 @@ "The Servo project developers", ] build = "build.rs" +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false description = "Automatically generates Rust FFI bindings to C and C++ libraries." homepage = "https://rust-lang.github.io/rust-bindgen/" documentation = "https://docs.rs/bindgen" -readme = "README.md" +readme = "../README.md" keywords = [ "bindings", "ffi", @@ -60,13 +65,30 @@ # {{version}} ({{date}})""" search = "# Unreleased" +[features] +__cli = [ + "dep:clap", + "dep:clap_complete", +] +__testing_only_extra_assertions = [] +__testing_only_libclang_16 = [] +__testing_only_libclang_9 = [] +default = [ + "logging", + "prettyplease", + "runtime", +] +experimental = ["dep:annotate-snippets"] +logging = ["dep:log"] +runtime = ["clang-sys/runtime"] +static = ["clang-sys/static"] + [lib] name = "bindgen" path = "lib.rs" [dependencies.annotate-snippets] -version = "0.9.1" -features = ["color"] +version = "0.11.4" optional = true [dependencies.bitflags] @@ -77,18 +99,21 @@ [dependencies.clang-sys] version = "1" -features = ["clang_6_0"] +features = ["clang_11_0"] +[dependencies.clap] +version = "4" +features = ["derive"] +optional = true + +[dependencies.clap_complete] +version = "4" +optional = true + [dependencies.itertools] -version = ">=0.10,<0.13" +version = ">=0.10,<0.15" default-features = false -[dependencies.lazy_static] -version = "1" - -[dependencies.lazycell] -version = "1" - [dependencies.log] version = "0.4" optional = true @@ -99,15 +124,14 @@ optional = true [dependencies.proc-macro2] -version = "1" -default-features = false +version = "1.0.80" [dependencies.quote] version = "1" default-features = false [dependencies.regex] -version = "1.5.1" +version = "1.5.3" features = [ "std", "unicode-perl", @@ -115,7 +139,7 @@ default-features = false [dependencies.rustc-hash] -version = "1.0.1" +version = "2.1.0" [dependencies.shlex] version = "1" @@ -128,24 +152,38 @@ "visit-mut", ] -[dependencies.which] -version = "4.2.1" -optional = true -default-features = false +[lints.clippy] +cast_possible_truncation = "allow" +cast_possible_wrap = "allow" +cast_precision_loss = "allow" +cast_sign_loss = "allow" +default_trait_access = "allow" +enum_glob_use = "allow" +ignored_unit_patterns = "allow" +implicit_hasher = "allow" +items_after_statements = "allow" +match_same_arms = "allow" +maybe_infinite_iter = "allow" +missing_errors_doc = "allow" +missing_panics_doc = "allow" +module_name_repetitions = "allow" +must_use_candidate = "allow" +redundant_closure_for_method_calls = "allow" +return_self_not_must_use = "allow" +similar_names = "allow" +struct_excessive_bools = "allow" +struct_field_names = "allow" +too_many_lines = "allow" +trivially_copy_pass_by_ref = "allow" +unnecessary_wraps = "allow" +unreadable_literal = "allow" +unused_self = "allow" +used_underscore_binding = "allow" +wildcard_imports = "allow" -[features] -__cli = [] -__testing_only_extra_assertions = [] -__testing_only_libclang_16 = [] -__testing_only_libclang_9 = [] -default = [ - "logging", - "prettyplease", - "runtime", - "which-rustfmt", -] -experimental = ["dep:annotate-snippets"] -logging = ["dep:log"] -runtime = ["clang-sys/runtime"] -static = ["clang-sys/static"] -which-rustfmt = ["dep:which"] +[lints.clippy.pedantic] +level = "warn" +priority = -1 + +[lints.rust] +unused_qualifications = "warn" diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/README.md firefox-140.10.2/third_party/rust/bindgen/README.md --- firefox-140.10.2.orig/third_party/rust/bindgen/README.md Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/README.md Thu Jan 1 01:00:00 1970 @@ -1,89 +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 `bindgen` minimum supported Rust version is **1.60.0**. - -The `bindgen-cli` minimum supported Rust version is **1.64.0**. - -No MSRV bump policy has been established yet, so MSRV may increase in any release. - -The MSRV is the minimum Rust version that can be used to *compile* each crate. However, `bindgen` and `bindgen-cli` can generate bindings that are compatible with Rust versions below the current MSRV. - -Most of the time, the `bindgen-cli` crate will have a more recent MSRV than `bindgen` as crates such as `clap` require it. - -## API Reference - -[API reference documentation is on docs.rs](https://docs.rs/bindgen) - -## Environment Variables - -In addition to the [library API](https://docs.rs/bindgen) and [executable command-line API][bindgen-cmdline], -`bindgen` can be controlled through environment variables. - -End-users should set these environment variables to modify `bindgen`'s behavior without modifying the source code of direct consumers of `bindgen`. - -- `BINDGEN_EXTRA_CLANG_ARGS`: extra arguments to pass to `clang` - - Arguments are whitespace-separated - - Use shell-style quoting to pass through whitespace - - Examples: - - Specify alternate sysroot: `--sysroot=/path/to/sysroot` - - Add include search path with spaces: `-I"/path/with spaces"` -- `BINDGEN_EXTRA_CLANG_ARGS_`: 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 -rNu firefox-140.10.2.orig/third_party/rust/bindgen/build.rs firefox-140.10.2/third_party/rust/bindgen/build.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/build.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/build.rs Mon May 11 04:49:32 2026 @@ -20,10 +20,10 @@ println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS"); println!( "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}", - std::env::var("TARGET").unwrap() + env::var("TARGET").unwrap() ); println!( "cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_{}", - std::env::var("TARGET").unwrap().replace('-', "_") + env::var("TARGET").unwrap().replace('-', "_") ); } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/callbacks.rs firefox-140.10.2/third_party/rust/bindgen/callbacks.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/callbacks.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/callbacks.rs Mon May 11 04:49:32 2026 @@ -4,24 +4,21 @@ pub use crate::ir::derive::CanDerive as ImplementsTrait; pub use crate::ir::enum_ty::{EnumVariantCustomBehavior, EnumVariantValue}; pub use crate::ir::int::IntKind; +pub use cexpr::token::Kind as TokenKind; +pub use cexpr::token::Token; use std::fmt; /// An enum to allow ignoring parsing of macros. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub enum MacroParsingBehavior { /// Ignore the macro, generating no code for it, or anything that depends on /// it. Ignore, /// The default behavior bindgen would have otherwise. + #[default] Default, } -impl Default for MacroParsingBehavior { - fn default() -> Self { - MacroParsingBehavior::Default - } -} - /// A trait to allow configuring different kinds of types in different /// situations. pub trait ParseCallbacks: fmt::Debug { @@ -54,6 +51,9 @@ None } + /// Modify the contents of a macro + fn modify_macro(&self, _name: &str, _tokens: &mut Vec) {} + /// 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 { @@ -94,8 +94,8 @@ None } - /// Allows to rename an item, replacing `_original_item_name`. - fn item_name(&self, _original_item_name: &str) -> Option { + /// Allows to rename an item, replacing `_item_info.name`. + fn item_name(&self, _item_info: ItemInfo) -> Option { None } @@ -134,6 +134,14 @@ vec![] } + /// Provide a list of custom attributes. + /// + /// If no additional attributes are wanted, this function should return an + /// empty `Vec`. + fn add_attributes(&self, _info: &AttributeInfo<'_>) -> Vec { + vec![] + } + /// Process a source code comment. fn process_comment(&self, _comment: &str) -> Option { None @@ -159,11 +167,94 @@ fn wrap_as_variadic_fn(&self, _name: &str) -> Option { None } + + /// This will get called everytime an item (currently struct, union, and alias) is found with some information about it + fn new_item_found( + &self, + _id: DiscoveredItemId, + _item: DiscoveredItem, + _source_location: Option<&SourceLocation>, + ) { + } + + // TODO add callback for ResolvedTypeRef } +/// An identifier for a discovered item. Used to identify an aliased type (see [`DiscoveredItem::Alias`]) +#[derive(Ord, PartialOrd, PartialEq, Eq, Hash, Debug, Clone, Copy)] +pub struct DiscoveredItemId(usize); + +impl DiscoveredItemId { + /// Constructor + pub fn new(value: usize) -> Self { + Self(value) + } +} + +/// Struct passed to [`ParseCallbacks::new_item_found`] containing information about discovered +/// items (struct, union, and alias) +#[derive(Debug, Hash, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub enum DiscoveredItem { + /// Represents a struct with its original name in C and its generated binding name + Struct { + /// The original name (learnt from C) of the structure + /// Can be None if the union is anonymous. + original_name: Option, + + /// The name of the generated binding + final_name: String, + }, + + /// Represents a union with its original name in C and its generated binding name + Union { + /// The original name (learnt from C) of the structure. + /// Can be None if the union is anonymous. + original_name: Option, + + /// The name of the generated binding + final_name: String, + }, + + /// Represents an alias like a typedef + /// ```c + /// typedef struct MyStruct { + /// ... + /// } StructAlias; + /// ``` + /// Here, the name of the alias is `StructAlias` and it's an alias for `MyStruct` + Alias { + /// The name of the alias in C (`StructAlias`) + alias_name: String, + + /// The identifier of the discovered type + alias_for: DiscoveredItemId, + }, + + /// Represents an enum. + Enum { + /// The final name of the generated binding + final_name: String, + }, + + /// A function or method. + Function { + /// The final name used. + final_name: String, + }, + + /// A method. + Method { + /// The final name used. + final_name: String, + + /// Type to which this method belongs. + parent: DiscoveredItemId, + }, // modules, etc. +} + /// Relevant information about a type to which new derive attributes will be added using /// [`ParseCallbacks::add_derives`]. -#[derive(Debug)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub struct DeriveInfo<'a> { /// The name of the type. @@ -172,7 +263,18 @@ pub kind: TypeKind, } +/// Relevant information about a type to which new attributes will be added using +/// [`ParseCallbacks::add_attributes`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub struct AttributeInfo<'a> { + /// The name of the type. + pub name: &'a str, + /// The kind of the type. + pub kind: TypeKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] /// The kind of the current type. pub enum TypeKind { /// The type is a Rust `struct`. @@ -184,6 +286,7 @@ } /// A struct providing information about the item being passed to [`ParseCallbacks::generated_name_override`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub struct ItemInfo<'a> { /// The name of the item @@ -192,9 +295,14 @@ pub kind: ItemKind, } -/// An enum indicating the kind of item for an ItemInfo. +/// An enum indicating the kind of item for an `ItemInfo`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub enum ItemKind { + /// A module + Module, + /// A type + Type, /// A Function Function, /// A Variable @@ -203,11 +311,27 @@ /// Relevant information about a field for which visibility can be determined using /// [`ParseCallbacks::field_visibility`]. -#[derive(Debug)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[non_exhaustive] pub struct FieldInfo<'a> { /// The name of the type. pub type_name: &'a str, /// The name of the field. pub field_name: &'a str, + /// The name of the type of the field. + pub field_type_name: Option<&'a str>, +} + +/// Location in the source code. Roughly equivalent to the same type +/// within `clang_sys`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SourceLocation { + /// Line number. + pub line: usize, + /// Column number within line. + pub col: usize, + /// Byte offset within file. + pub byte_offset: usize, + /// Filename, if known. + pub file_name: Option, } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/clang.rs firefox-140.10.2/third_party/rust/bindgen/clang.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/clang.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/clang.rs Mon May 11 04:49:32 2026 @@ -10,9 +10,11 @@ use std::ffi::{CStr, CString}; use std::fmt; +use std::fs::OpenOptions; use std::hash::Hash; use std::hash::Hasher; use std::os::raw::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ulonglong}; +use std::sync::OnceLock; use std::{mem, ptr, slice}; /// Type representing a clang attribute. @@ -214,10 +216,10 @@ }) .or_else(|| { let canonical = self.canonical(); - if canonical != *self { - canonical.num_template_args() - } else { + if canonical == *self { None + } else { + canonical.num_template_args() } }) } @@ -492,7 +494,7 @@ where Visitor: FnMut(Cursor) -> CXChildVisitResult, { - let data = &mut visitor as *mut Visitor; + let data = ptr::addr_of_mut!(visitor); unsafe { clang_visitChildren(self.x, visit_children::, data.cast()); } @@ -786,7 +788,7 @@ 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) || + if attr.kind == Some(kind) || (kind == CXCursor_UnexposedAttr && cur.tokens().iter().any(|t| { t.kind == attr.token_kind && @@ -874,9 +876,9 @@ unsafe { clang_getCXXAccessSpecifier(self.x) } } - /// Is the cursor's referrent publically accessible in C++? + /// Is the cursor's referent publicly accessible in C++? /// - /// Returns true if self.access_specifier() is `CX_CXXPublic` or + /// Returns true if `self.access_specifier()` is `CX_CXXPublic` or /// `CX_CXXInvalidAccessSpecifier`. pub(crate) fn public_accessible(&self) -> bool { let access = self.access_specifier(); @@ -943,7 +945,7 @@ } /// Gets the tokens that correspond to that cursor. - pub(crate) fn tokens(&self) -> RawTokens { + pub(crate) fn tokens(&self) -> RawTokens<'_> { RawTokens::new(self) } @@ -955,19 +957,22 @@ .collect() } - /// Obtain the real path name of a cursor of InclusionDirective kind. + /// Obtain the real path name of a cursor of `InclusionDirective` kind. /// /// Returns None if the cursor does not include a file, otherwise the file's full name pub(crate) fn get_included_file_name(&self) -> Option { - let file = unsafe { clang_sys::clang_getIncludedFile(self.x) }; + let file = unsafe { clang_getIncludedFile(self.x) }; if file.is_null() { None } else { - Some(unsafe { - cxstring_into_string(clang_sys::clang_getFileName(file)) - }) + Some(unsafe { cxstring_into_string(clang_getFileName(file)) }) } } + + /// Is this cursor's referent a namespace that is inline? + pub(crate) fn is_inline_namespace(&self) -> bool { + unsafe { clang_Cursor_isInlineNamespace(self.x) != 0 } + } } /// A struct that owns the tokenizer result from a given cursor. @@ -1001,7 +1006,7 @@ } /// Get an iterator over these tokens. - pub(crate) fn iter(&self) -> ClangTokenIterator { + pub(crate) fn iter(&self) -> ClangTokenIterator<'_> { ClangTokenIterator { tu: self.tu, raw: self.as_slice().iter(), @@ -1009,7 +1014,7 @@ } } -impl<'a> Drop for RawTokens<'a> { +impl Drop for RawTokens<'_> { fn drop(&mut self) { if !self.tokens.is_null() { unsafe { @@ -1040,13 +1045,11 @@ impl ClangToken { /// Get the token spelling, without being converted to utf-8. pub(crate) fn spelling(&self) -> &[u8] { - let c_str = unsafe { - CStr::from_ptr(clang_getCString(self.spelling) as *const _) - }; + let c_str = unsafe { CStr::from_ptr(clang_getCString(self.spelling)) }; c_str.to_bytes() } - /// Converts a ClangToken to a `cexpr` token if possible. + /// Converts a `ClangToken` to a `cexpr` token if possible. pub(crate) fn as_cexpr_token(&self) -> Option { use cexpr::token; @@ -1059,7 +1062,7 @@ // expressions, so we strip them down here. CXToken_Comment => return None, _ => { - warn!("Found unexpected token kind: {:?}", self); + warn!("Found unexpected token kind: {self:?}"); return None; } }; @@ -1083,7 +1086,7 @@ raw: slice::Iter<'a, CXToken>, } -impl<'a> Iterator for ClangTokenIterator<'a> { +impl Iterator for ClangTokenIterator<'_> { type Item = ClangToken; fn next(&mut self) -> Option { @@ -1093,9 +1096,9 @@ let spelling = clang_getTokenSpelling(self.tu, *raw); let extent = clang_getTokenExtent(self.tu, *raw); Some(ClangToken { - kind, - extent, spelling, + extent, + kind, }) } } @@ -1105,10 +1108,8 @@ /// (including '_') and does not start with a digit. pub(crate) fn is_valid_identifier(name: &str) -> bool { let mut chars = name.chars(); - let first_valid = chars - .next() - .map(|c| c.is_alphabetic() || c == '_') - .unwrap_or(false); + let first_valid = + chars.next().is_some_and(|c| c.is_alphabetic() || c == '_'); first_valid && chars.all(|c| c.is_alphanumeric() || c == '_') } @@ -1121,7 +1122,7 @@ where Visitor: FnMut(Cursor) -> CXChildVisitResult, { - let func: &mut Visitor = unsafe { &mut *(data as *mut Visitor) }; + let func: &mut Visitor = unsafe { &mut *data.cast::() }; let child = Cursor { x: cur }; (*func)(child) @@ -1137,7 +1138,7 @@ impl Hash for Cursor { fn hash(&self, state: &mut H) { - unsafe { clang_hashCursor(self.x) }.hash(state) + unsafe { clang_hashCursor(self.x) }.hash(state); } } @@ -1210,11 +1211,11 @@ /// Get a cursor pointing to this type's declaration. pub(crate) fn declaration(&self) -> Cursor { - unsafe { - Cursor { - x: clang_getTypeDeclaration(self.x), - } - } + let decl = Cursor { + x: unsafe { clang_getTypeDeclaration(self.x) }, + }; + // Prior to clang 22, the declaration pointed to the definition. + decl.definition().unwrap_or(decl) } /// Get the canonical declaration of this type, if it is available. @@ -1440,10 +1441,10 @@ /// elements. pub(crate) fn num_elements(&self) -> Option { let num_elements_returned = unsafe { clang_getNumElements(self.x) }; - if num_elements_returned != -1 { - Some(num_elements_returned as usize) - } else { + if num_elements_returned == -1 { None + } else { + Some(num_elements_returned as usize) } } @@ -1491,6 +1492,15 @@ } } + /// For atomic types, get the underlying type. + pub(crate) fn atomic_value_type(&self) -> Type { + unsafe { + Type { + x: clang_Type_getValueType(self.x), + } + } + } + /// Is this a valid type? pub(crate) fn is_valid(&self) -> bool { self.kind() != CXType_Invalid @@ -1506,7 +1516,7 @@ // Yep, the spelling of this containing type-parameter is extremely // nasty... But can happen in . Unfortunately I couldn't // reduce it enough :( - self.template_args().map_or(false, |args| args.len() > 0) && + self.template_args().is_some_and(|args| args.len() > 0) && !matches!( self.declaration().kind(), CXCursor_ClassTemplatePartialSpecialization | @@ -1527,13 +1537,13 @@ pub(crate) fn is_associated_type(&self) -> bool { // This is terrible :( fn hacky_parse_associated_type>(spelling: S) -> bool { - lazy_static! { - static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new( - r"typename type\-parameter\-\d+\-\d+::.+" - ) - .unwrap(); - } - ASSOC_TYPE_RE.is_match(spelling.as_ref()) + static ASSOC_TYPE_RE: OnceLock = OnceLock::new(); + ASSOC_TYPE_RE + .get_or_init(|| { + regex::Regex::new(r"typename type\-parameter\-\d+\-\d+::.+") + .unwrap() + }) + .is_match(spelling.as_ref()) } self.kind() == CXType_Unexposed && @@ -1620,7 +1630,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (file, line, col, _) = self.location(); if let Some(name) = file.name() { - write!(f, "{}:{}:{}", name, line, col) + write!(f, "{name}:{line}:{col}") } else { "builtin definitions".fmt(f) } @@ -1629,7 +1639,7 @@ impl fmt::Debug for SourceLocation { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self) + write!(f, "{self}") } } @@ -1749,9 +1759,9 @@ fn cxstring_to_string_leaky(s: CXString) -> String { if s.data.is_null() { - return "".to_owned(); + return String::new(); } - let c_str = unsafe { CStr::from_ptr(clang_getCString(s) as *const _) }; + let c_str = unsafe { CStr::from_ptr(clang_getCString(s)) }; c_str.to_string_lossy().into_owned() } @@ -1777,7 +1787,7 @@ pub(crate) fn new(pch: bool, diag: bool) -> Index { unsafe { Index { - x: clang_createIndex(pch as c_int, diag as c_int), + x: clang_createIndex(c_int::from(pch), c_int::from(diag)), } } } @@ -1868,6 +1878,25 @@ } } + /// Save a translation unit to the given file. + pub(crate) fn save(&mut self, file: &str) -> Result<(), CXSaveError> { + let Ok(file) = CString::new(file) else { + return Err(CXSaveError_Unknown); + }; + let ret = unsafe { + clang_saveTranslationUnit( + self.x, + file.as_ptr(), + clang_defaultSaveOptions(self.x), + ) + }; + if ret != 0 { + Err(ret) + } else { + Ok(()) + } + } + /// Is this the null translation unit? pub(crate) fn is_null(&self) -> bool { self.x.is_null() @@ -1882,6 +1911,87 @@ } } +/// Translation unit used for macro fallback parsing +pub(crate) struct FallbackTranslationUnit { + file_path: String, + pch_path: String, + idx: Box, + tu: TranslationUnit, +} + +impl fmt::Debug for FallbackTranslationUnit { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "FallbackTranslationUnit {{ }}") + } +} + +impl FallbackTranslationUnit { + /// Create a new fallback translation unit + pub(crate) fn new( + file: String, + pch_path: String, + c_args: &[Box], + ) -> Option { + // Create empty file + OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&file) + .ok()?; + + let f_index = Box::new(Index::new(true, false)); + let f_translation_unit = TranslationUnit::parse( + &f_index, + &file, + c_args, + &[], + CXTranslationUnit_None, + )?; + Some(FallbackTranslationUnit { + file_path: file, + pch_path, + tu: f_translation_unit, + idx: f_index, + }) + } + + /// Get reference to underlying translation unit. + pub(crate) fn translation_unit(&self) -> &TranslationUnit { + &self.tu + } + + /// Reparse a translation unit. + pub(crate) fn reparse( + &mut self, + unsaved_contents: &str, + ) -> Result<(), CXErrorCode> { + let unsaved = &[UnsavedFile::new(&self.file_path, unsaved_contents)]; + let mut c_unsaved: Vec = + unsaved.iter().map(|f| f.x).collect(); + let ret = unsafe { + clang_reparseTranslationUnit( + self.tu.x, + unsaved.len() as c_uint, + c_unsaved.as_mut_ptr(), + clang_defaultReparseOptions(self.tu.x), + ) + }; + if ret != 0 { + Err(ret) + } else { + Ok(()) + } + } +} + +impl Drop for FallbackTranslationUnit { + fn drop(&mut self) { + let _ = std::fs::remove_file(&self.file_path); + let _ = std::fs::remove_file(&self.pch_path); + } +} + /// A diagnostic message generated while parsing a translation unit. pub(crate) struct Diagnostic { x: CXDiagnostic, @@ -1968,26 +2078,25 @@ let prefix = prefix.as_ref(); print_indent( depth, - format!(" {}kind = {}", prefix, kind_to_str(c.kind())), + format!(" {prefix}kind = {}", kind_to_str(c.kind())), ); print_indent( depth, - format!(" {}spelling = \"{}\"", prefix, c.spelling()), + format!(" {prefix}spelling = \"{}\"", c.spelling()), ); - print_indent(depth, format!(" {}location = {}", prefix, c.location())); + print_indent(depth, format!(" {prefix}location = {}", c.location())); print_indent( depth, - format!(" {}is-definition? {}", prefix, c.is_definition()), + format!(" {prefix}is-definition? {}", c.is_definition()), ); print_indent( depth, - format!(" {}is-declaration? {}", prefix, c.is_declaration()), + format!(" {prefix}is-declaration? {}", c.is_declaration()), ); print_indent( depth, format!( - " {}is-inlined-function? {}", - prefix, + " {prefix}is-inlined-function? {}", c.is_inlined_function() ), ); @@ -1996,23 +2105,19 @@ if templ_kind != CXCursor_NoDeclFound { print_indent( depth, - format!( - " {}template-kind = {}", - prefix, - kind_to_str(templ_kind) - ), + format!(" {prefix}template-kind = {}", kind_to_str(templ_kind)), ); } if let Some(usr) = c.usr() { - print_indent(depth, format!(" {}usr = \"{}\"", prefix, usr)); + print_indent(depth, format!(" {prefix}usr = \"{usr}\"")); } if let Ok(num) = c.num_args() { - print_indent(depth, format!(" {}number-of-args = {}", prefix, num)); + print_indent(depth, format!(" {prefix}number-of-args = {num}")); } if let Some(num) = c.num_template_args() { print_indent( depth, - format!(" {}number-of-template-args = {}", prefix, num), + format!(" {prefix}number-of-template-args = {num}"), ); } @@ -2021,28 +2126,28 @@ Some(w) => w.to_string(), None => "".to_string(), }; - print_indent(depth, format!(" {}bit-width = {}", prefix, width)); + print_indent(depth, format!(" {prefix}bit-width = {width}")); } if let Some(ty) = c.enum_type() { print_indent( depth, - format!(" {}enum-type = {}", prefix, type_to_str(ty.kind())), + format!(" {prefix}enum-type = {}", type_to_str(ty.kind())), ); } if let Some(val) = c.enum_val_signed() { - print_indent(depth, format!(" {}enum-val = {}", prefix, val)); + print_indent(depth, format!(" {prefix}enum-val = {val}")); } if let Some(ty) = c.typedef_type() { print_indent( depth, - format!(" {}typedef-type = {}", prefix, type_to_str(ty.kind())), + format!(" {prefix}typedef-type = {}", type_to_str(ty.kind())), ); } if let Some(ty) = c.ret_type() { print_indent( depth, - format!(" {}ret-type = {}", prefix, type_to_str(ty.kind())), + format!(" {prefix}ret-type = {}", type_to_str(ty.kind())), ); } @@ -2092,16 +2197,16 @@ let prefix = prefix.as_ref(); let kind = ty.kind(); - print_indent(depth, format!(" {}kind = {}", prefix, type_to_str(kind))); + print_indent(depth, format!(" {prefix}kind = {}", type_to_str(kind))); if kind == CXType_Invalid { return; } - print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv())); + print_indent(depth, format!(" {prefix}cconv = {}", ty.call_conv())); print_indent( depth, - format!(" {}spelling = \"{}\"", prefix, ty.spelling()), + format!(" {prefix}spelling = \"{}\"", ty.spelling()), ); let num_template_args = unsafe { clang_Type_getNumTemplateArguments(ty.x) }; @@ -2109,20 +2214,16 @@ print_indent( depth, format!( - " {}number-of-template-args = {}", - prefix, num_template_args + " {prefix}number-of-template-args = {num_template_args}" ), ); } if let Some(num) = ty.num_elements() { - print_indent( - depth, - format!(" {}number-of-elements = {}", prefix, num), - ); + print_indent(depth, format!(" {prefix}number-of-elements = {num}")); } print_indent( depth, - format!(" {}is-variadic? {}", prefix, ty.is_variadic()), + format!(" {prefix}is-variadic? {}", ty.is_variadic()), ); let canonical = ty.canonical_type(); @@ -2250,7 +2351,7 @@ if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 { let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) }; - if value > i64::max_value() as c_ulonglong { + if value > i64::MAX as c_ulonglong { return None; } @@ -2258,10 +2359,10 @@ } let value = unsafe { clang_EvalResult_getAsLongLong(self.x) }; - if value > i64::max_value() as c_longlong { + if value > i64::MAX as c_longlong { return None; } - if value < i64::min_value() as c_longlong { + if value < i64::MIN as c_longlong { return None; } #[allow(clippy::unnecessary_cast)] diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/bitfield_unit.rs firefox-140.10.2/third_party/rust/bindgen/codegen/bitfield_unit.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/bitfield_unit.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/bitfield_unit.rs Mon May 11 04:49:32 2026 @@ -16,12 +16,7 @@ Storage: AsRef<[u8]> + AsMut<[u8]>, { #[inline] - pub fn get_bit(&self, index: usize) -> bool { - debug_assert!(index / 8 < self.storage.as_ref().len()); - - let byte_index = index / 8; - let byte = self.storage.as_ref()[byte_index]; - + fn extract_bit(byte: u8, index: usize) -> bool { let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { @@ -34,12 +29,30 @@ } #[inline] - pub fn set_bit(&mut self, index: usize, val: bool) { + pub fn get_bit(&self, index: usize) -> bool { debug_assert!(index / 8 < self.storage.as_ref().len()); let byte_index = index / 8; - let byte = &mut self.storage.as_mut()[byte_index]; + let byte = self.storage.as_ref()[byte_index]; + Self::extract_bit(byte, index) + } + + #[inline] + pub unsafe fn raw_get_bit(this: *const Self, index: usize) -> bool { + debug_assert!(index / 8 < core::mem::size_of::()); + + let byte_index = index / 8; + let byte = unsafe { + *(core::ptr::addr_of!((*this).storage) as *const u8) + .offset(byte_index as isize) + }; + + Self::extract_bit(byte, index) + } + + #[inline] + fn change_bit(byte: u8, index: usize, val: bool) -> u8 { let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { @@ -48,13 +61,36 @@ let mask = 1 << bit_index; if val { - *byte |= mask; + byte | mask } else { - *byte &= !mask; + byte & !mask } } #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + + *byte = Self::change_bit(*byte, index, val); + } + + #[inline] + pub unsafe fn raw_set_bit(this: *mut Self, index: usize, val: bool) { + debug_assert!(index / 8 < core::mem::size_of::()); + + let byte_index = index / 8; + let byte = unsafe { + (core::ptr::addr_of_mut!((*this).storage) as *mut u8) + .offset(byte_index as isize) + }; + + unsafe { *byte = Self::change_bit(*byte, index, val) }; + } + + #[inline] pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); @@ -80,6 +116,35 @@ } #[inline] + pub unsafe fn raw_get( + this: *const Self, + bit_offset: usize, + bit_width: u8, + ) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= + core::mem::size_of::() + ); + + let mut val = 0; + + for i in 0..(bit_width as usize) { + if unsafe { Self::raw_get_bit(this, i + bit_offset) } { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + + val + } + + #[inline] pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { debug_assert!(bit_width <= 64); debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); @@ -97,6 +162,34 @@ i }; self.set_bit(index + bit_offset, val_bit_is_set); + } + } + + #[inline] + pub unsafe fn raw_set( + this: *mut Self, + bit_offset: usize, + bit_width: u8, + val: u64, + ) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < core::mem::size_of::()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= + core::mem::size_of::() + ); + + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + unsafe { + Self::raw_set_bit(this, index + bit_offset, val_bit_is_set) + }; } } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs firefox-140.10.2/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/bitfield_unit_tests.rs Mon May 11 04:49:32 2026 @@ -33,7 +33,7 @@ } println!(); - println!("bits = {:?}", bits); + println!("bits = {bits:?}"); assert_eq!( bits, &[ @@ -88,8 +88,8 @@ let actual = unit.get($start, $len); println!(); - println!("expected = {:064b}", expected); - println!("actual = {:064b}", actual); + println!("expected = {expected:064b}"); + println!("actual = {actual:064b}"); assert_eq!(expected, actual); })* @@ -191,7 +191,7 @@ println!(); println!("set({}, {}, {:032b}", $start, $len, $val); println!("expected = {:064b}", $expected); - println!("actual = {:064b}", actual); + println!("actual = {actual:064b}"); assert_eq!($expected, actual); )* diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/dyngen.rs firefox-140.10.2/third_party/rust/bindgen/codegen/dyngen.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/dyngen.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/dyngen.rs Mon May 11 04:49:32 2026 @@ -1,7 +1,7 @@ use crate::codegen; use crate::ir::context::BindgenContext; use crate::ir::function::ClangAbi; -use proc_macro2::Ident; +use proc_macro2::{Ident, TokenStream}; /// Used to build the output tokens for dynamic bindings. #[derive(Default)] @@ -14,7 +14,7 @@ /// ... /// } /// ``` - struct_members: Vec, + struct_members: Vec, /// Tracks the tokens that will appear inside the library struct's implementation, e.g.: /// @@ -26,7 +26,7 @@ /// } /// } /// ``` - struct_implementation: Vec, + struct_implementation: Vec, /// Tracks the initialization of the fields inside the `::new` constructor of the library /// struct, e.g.: @@ -45,7 +45,7 @@ /// ... /// } /// ``` - constructor_inits: Vec, + constructor_inits: Vec, /// Tracks the information that is passed to the library struct at the end of the `::new` /// constructor, e.g.: @@ -65,7 +65,7 @@ /// } /// } /// ``` - init_fields: Vec, + init_fields: Vec, } impl DynamicItems { @@ -75,14 +75,20 @@ pub(crate) fn get_tokens( &self, - lib_ident: Ident, + lib_ident: &Ident, ctx: &BindgenContext, - ) -> proc_macro2::TokenStream { + ) -> TokenStream { let struct_members = &self.struct_members; let constructor_inits = &self.constructor_inits; let init_fields = &self.init_fields; let struct_implementation = &self.struct_implementation; + let library_new = if ctx.options().wrap_unsafe_ops { + quote!(unsafe { ::libloading::Library::new(path) }) + } else { + quote!(::libloading::Library::new(path)) + }; + let from_library = if ctx.options().wrap_unsafe_ops { quote!(unsafe { Self::from_library(library) }) } else { @@ -90,8 +96,6 @@ }; quote! { - extern crate libloading; - pub struct #lib_ident { __library: ::libloading::Library, #(#struct_members)* @@ -102,7 +106,7 @@ path: P ) -> Result where P: AsRef<::std::ffi::OsStr> { - let library = ::libloading::Library::new(path)?; + let library = #library_new?; #from_library } @@ -124,17 +128,18 @@ } #[allow(clippy::too_many_arguments)] - pub(crate) fn push( + pub(crate) fn push_func( &mut self, - ident: Ident, + ident: &Ident, + symbol: &str, abi: ClangAbi, is_variadic: bool, is_required: bool, - args: Vec, - args_identifiers: Vec, - ret: proc_macro2::TokenStream, - ret_ty: proc_macro2::TokenStream, - attributes: Vec, + args: &[TokenStream], + args_identifiers: &[TokenStream], + ret: &TokenStream, + ret_ty: &TokenStream, + attributes: &[TokenStream], ctx: &BindgenContext, ) { if !is_variadic { @@ -177,11 +182,12 @@ } // 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 symbol_cstr = + codegen::helpers::ast_ty::cstr_expr(symbol.to_string()); let library_get = if ctx.options().wrap_unsafe_ops { - quote!(unsafe { __library.get(#ident_str) }) + quote!(unsafe { __library.get(#symbol_cstr) }) } else { - quote!(__library.get(#ident_str)) + quote!(__library.get(#symbol_cstr)) }; self.constructor_inits.push(if is_required { @@ -193,6 +199,57 @@ let #ident = #library_get.map(|sym| *sym); } }); + + self.init_fields.push(quote! { + #ident + }); + } + + pub fn push_var( + &mut self, + ident: &Ident, + symbol: &str, + ty: &TokenStream, + is_required: bool, + wrap_unsafe_ops: bool, + ) { + let member = if is_required { + quote! { *mut #ty } + } else { + quote! { Result<*mut #ty, ::libloading::Error> } + }; + + self.struct_members.push(quote! { + pub #ident: #member, + }); + + let deref = if is_required { + quote! { self.#ident } + } else { + quote! { *self.#ident.as_ref().expect("Expected variable, got error.") } + }; + self.struct_implementation.push(quote! { + pub unsafe fn #ident (&self) -> *mut #ty { + #deref + } + }); + + let symbol_cstr = + codegen::helpers::ast_ty::cstr_expr(symbol.to_string()); + + let library_get = if wrap_unsafe_ops { + quote!(unsafe { __library.get::<*mut #ty>(#symbol_cstr) }) + } else { + quote!(__library.get::<*mut #ty>(#symbol_cstr)) + }; + + let qmark = if is_required { quote!(?) } else { quote!() }; + + let var_get = quote! { + let #ident = #library_get.map(|sym| *sym)#qmark; + }; + + self.constructor_inits.push(var_get); self.init_fields.push(quote! { #ident diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/error.rs firefox-140.10.2/third_party/rust/bindgen/codegen/error.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/error.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/error.rs Mon May 11 04:49:32 2026 @@ -36,12 +36,11 @@ Error::UnsupportedAbi(abi) => { write!( f, - "{} ABI is not supported by the configured Rust target.", - abi + "{abi} ABI is not supported by the configured Rust target." ) } Error::InvalidPointerSize { ty_name, ty_size, ptr_size } => { - write!(f, "The {} pointer type has size {} but the current target's pointer size is {}.", ty_name, ty_size, ptr_size) + write!(f, "The {ty_name} pointer type has size {ty_size} but the current target's pointer size is {ptr_size}.") } } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/helpers.rs firefox-140.10.2/third_party/rust/bindgen/codegen/helpers.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/helpers.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/helpers.rs Mon May 11 04:49:32 2026 @@ -1,7 +1,10 @@ //! Helpers for code generation that don't need macro expansion. +use proc_macro2::{Ident, Span}; + use crate::ir::context::BindgenContext; use crate::ir::layout::Layout; +use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT; pub(crate) mod attributes { use proc_macro2::{Ident, Span, TokenStream}; @@ -17,7 +20,6 @@ pub(crate) fn repr_list(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() - .cloned() .map(|one| TokenStream::from_str(one).expect("repr to be valid")); quote! { #[repr( #( #which_ones ),* )] @@ -27,7 +29,6 @@ pub(crate) fn derives(which_ones: &[&str]) -> TokenStream { let which_ones = which_ones .iter() - .cloned() .map(|one| TokenStream::from_str(one).expect("derive to be valid")); quote! { #[derive( #( #which_ones ),* )] @@ -52,7 +53,7 @@ } } - pub(crate) fn doc(comment: String) -> TokenStream { + pub(crate) fn doc(comment: &str) -> TokenStream { if comment.is_empty() { quote!() } else { @@ -66,7 +67,7 @@ let name: Cow<'_, str> = if MANGLE { name.into() } else { - format!("\u{1}{}", name).into() + format!("\u{1}{name}").into() }; quote! { @@ -75,44 +76,58 @@ } } -/// Generates a proper type for a field or type with a given `Layout`, that is, -/// a type with the correct size and alignment restrictions. -pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> syn::Type { - let opaque = layout.opaque(); +/// The `ffi_safe` argument should be true if this is a type that the user might +/// reasonably use, e.g. not struct padding, where the `__BindgenOpaqueArray` is +/// just noise. +/// TODO: Should this be `MaybeUninit`, since padding bytes are effectively +/// uninitialized? +pub(crate) fn blob( + ctx: &BindgenContext, + layout: Layout, + ffi_safe: bool, +) -> syn::Type { + let align = layout.align.max(1); + // For alignments <= 4, it holds that the integer type of the same size aligns to that same + // size. For bigger alignments that's not guaranteed, e.g. on x86 u64 is aligned to 4 bytes. + if align <= 4 { + let ty = Layout::known_type_for_size(align).unwrap(); + let len = layout.size / align; + return if len == 1 { + ty + } else if !ffi_safe && len <= RUST_DERIVE_IN_ARRAY_LIMIT { + syn::parse_quote! { [#ty; #len] } + } else { + ctx.generated_opaque_array(1); + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::__BindgenOpaqueArray<[#ty; #len]> } + } else { + syn::parse_quote! { __BindgenOpaqueArray<[#ty; #len]> } + } + }; + } - // FIXME(emilio, #412): We fall back to byte alignment, but there are - // some things that legitimately are more than 8-byte aligned. - // - // Eventually we should be able to `unwrap` here, but... - let ty = match opaque.known_rust_type_for_array(ctx) { - Some(ty) => ty, - None => { - warn!("Found unknown alignment on code generation!"); - syn::parse_quote! { u8 } - } - }; - - let data_len = opaque.array_size(ctx).unwrap_or(layout.size); - - if data_len == 1 { - ty + ctx.generated_opaque_array(align); + let ident = format_ident!("__BindgenOpaqueArray{}", align); + let size = layout.size; + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::#ident<[u8; #size]> } } else { - syn::parse_quote! { [ #ty ; #data_len ] } + syn::parse_quote! { #ident<[u8; #size]> } } } /// Integer type of the same size as the given `Layout`. -pub(crate) fn integer_type( - ctx: &BindgenContext, - layout: Layout, -) -> Option { - Layout::known_type_for_size(ctx, layout.size) +pub(crate) fn integer_type(layout: Layout) -> Option { + Layout::known_type_for_size(layout.size) } +pub(crate) const BITFIELD_UNIT: &str = "__BindgenBitfieldUnit"; + /// Generates a bitfield allocation unit type for a type with the given `Layout`. pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type { let size = layout.size; - let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> }; + let bitfield_unit_name = Ident::new(BITFIELD_UNIT, Span::call_site()); + let ty = syn::parse_quote! { #bitfield_unit_name<[u8; #size]> }; if ctx.options().enable_cxx_namespaces { return syn::parse_quote! { root::#ty }; @@ -126,7 +141,7 @@ use crate::ir::function::FunctionSig; use crate::ir::layout::Layout; use crate::ir::ty::{FloatKind, IntKind}; - use proc_macro2::{self, TokenStream}; + use proc_macro2::TokenStream; use std::str::FromStr; pub(crate) fn c_void(ctx: &BindgenContext) -> syn::Type { @@ -137,9 +152,7 @@ syn::parse_quote! { #prefix::c_void } } None => { - if ctx.options().use_core && - ctx.options().rust_features.core_ffi_c_void - { + if ctx.options().use_core { syn::parse_quote! { ::core::ffi::c_void } } else { syn::parse_quote! { ::std::os::raw::c_void } @@ -175,6 +188,12 @@ match ik { IntKind::Bool => syn::parse_quote! { bool }, IntKind::Char { .. } => raw_type(ctx, "c_char"), + // The following is used only when an unusual command-line + // argument is used. bindgen_cchar16_t is not a real type; + // but this allows downstream postprocessors to distinguish + // this case and do something special for C++ bindings + // containing the C++ type char16_t. + IntKind::Char16 => syn::parse_quote! { bindgen_cchar16_t }, IntKind::SChar => raw_type(ctx, "c_schar"), IntKind::UChar => raw_type(ctx, "c_uchar"), IntKind::Short => raw_type(ctx, "c_short"), @@ -188,7 +207,7 @@ IntKind::WChar => { let layout = layout.expect("Couldn't compute wchar_t's layout?"); - Layout::known_type_for_size(ctx, layout.size) + Layout::known_type_for_size(layout.size) .expect("Non-representable wchar_t?") } @@ -204,7 +223,7 @@ syn::parse_str(name).expect("Invalid integer type.") } IntKind::U128 => { - if ctx.options().rust_features.i128_and_u128 { + if true { syn::parse_quote! { u128 } } else { // Best effort thing, but wrong alignment @@ -213,7 +232,7 @@ } } IntKind::I128 => { - if ctx.options().rust_features.i128_and_u128 { + if true { syn::parse_quote! { i128 } } else { syn::parse_quote! { [u64; 2] } @@ -246,28 +265,25 @@ (FloatKind::Float, false) => raw_type(ctx, "c_float"), (FloatKind::Double, false) => raw_type(ctx, "c_double"), (FloatKind::LongDouble, _) => { - match layout { - Some(layout) => { - match layout.size { - 4 => syn::parse_quote! { f32 }, - 8 => syn::parse_quote! { f64 }, - // TODO(emilio): If rust ever gains f128 we should - // use it here and below. - _ => super::integer_type(ctx, layout) - .unwrap_or(syn::parse_quote! { f64 }), - } + if let Some(layout) = layout { + match layout.size { + 4 => syn::parse_quote! { f32 }, + 8 => syn::parse_quote! { f64 }, + // TODO(emilio): If rust ever gains f128 we should + // use it here and below. + _ => super::integer_type(layout) + .unwrap_or(syn::parse_quote! { f64 }), } - None => { - debug_assert!( - false, - "How didn't we know the layout for a primitive type?" - ); - syn::parse_quote! { f64 } - } + } else { + debug_assert!( + false, + "How didn't we know the layout for a primitive type?" + ); + syn::parse_quote! { f64 } } } (FloatKind::Float128, _) => { - if ctx.options().rust_features.i128_and_u128 { + if true { syn::parse_quote! { u128 } } else { syn::parse_quote! { [u64; 2] } @@ -296,37 +312,27 @@ } } - pub(crate) fn float_expr( - ctx: &BindgenContext, - f: f64, - ) -> Result { + pub(crate) fn float_expr(f: f64) -> Result { if f.is_finite() { let val = proc_macro2::Literal::f64_unsuffixed(f); return Ok(quote!(#val)); } - let prefix = ctx.trait_prefix(); - if f.is_nan() { - return Ok(quote! { - ::#prefix::f64::NAN - }); + return Ok(quote! { f64::NAN }); } if f.is_infinite() { - return Ok(if f.is_sign_positive() { - quote! { - ::#prefix::f64::INFINITY - } + let tokens = if f.is_sign_positive() { + quote! { f64::INFINITY } } else { - quote! { - ::#prefix::f64::NEG_INFINITY - } - }); + quote! { f64::NEG_INFINITY } + }; + return Ok(tokens); } - warn!("Unknown non-finite float number: {:?}", f); + warn!("Unknown non-finite float number: {f:?}"); Err(()) } @@ -338,17 +344,14 @@ signature .argument_types() .iter() - .map(|&(ref name, _ty)| match *name { - Some(ref name) => { - let name = ctx.rust_ident(name); - quote! { #name } - } - None => { + .map(|&(ref name, _ty)| { + let name = if let Some(ref name) = *name { + ctx.rust_ident(name) + } else { unnamed_arguments += 1; - let name = - ctx.rust_ident(format!("arg{}", unnamed_arguments)); - quote! { #name } - } + ctx.rust_ident(format!("arg{unnamed_arguments}")) + }; + quote! { #name } }) .collect() } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/impl_debug.rs firefox-140.10.2/third_party/rust/bindgen/codegen/impl_debug.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/impl_debug.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/impl_debug.rs Mon May 11 04:49:32 2026 @@ -1,7 +1,8 @@ use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods}; use crate::ir::context::BindgenContext; use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName}; -use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; +use crate::ir::ty::TypeKind; +use std::fmt::Write as _; pub(crate) fn gen_debug_impl( ctx: &BindgenContext, @@ -10,7 +11,7 @@ kind: CompKind, ) -> proc_macro2::TokenStream { let struct_name = item.canonical_name(ctx); - let mut format_string = format!("{} {{{{ ", struct_name); + let mut format_string = format!("{struct_name} {{{{ "); let mut tokens = vec![]; if item.is_opaque(ctx, &()) { @@ -64,7 +65,7 @@ ) -> Option<(String, Vec)>; } -impl<'a> ImplDebug<'a> for FieldData { +impl ImplDebug<'_> for FieldData { type Extra = (); fn impl_debug( @@ -80,7 +81,7 @@ } } -impl<'a> ImplDebug<'a> for BitfieldUnit { +impl ImplDebug<'_> for BitfieldUnit { type Extra = (); fn impl_debug( @@ -96,7 +97,7 @@ } if let Some(bitfield_name) = bitfield.name() { - format_string.push_str(&format!("{} : {{:?}}", bitfield_name)); + let _ = write!(format_string, "{bitfield_name} : {{:?}}"); let getter_name = bitfield.getter_name(); let name_ident = ctx.rust_ident_raw(getter_name); tokens.push(quote! { @@ -125,19 +126,14 @@ return None; } - let ty = match self.as_type() { - Some(ty) => ty, - None => { - return None; - } - }; + let ty = self.as_type()?; fn debug_print( name: &str, - name_ident: proc_macro2::TokenStream, + name_ident: &proc_macro2::TokenStream, ) -> Option<(String, Vec)> { Some(( - format!("{}: {{:?}}", name), + format!("{name}: {{:?}}"), vec![quote! { self.#name_ident }], @@ -158,60 +154,39 @@ TypeKind::ObjCInterface(..) | TypeKind::ObjCId | TypeKind::Comp(..) | - TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }), + TypeKind::ObjCSel => debug_print(name, "e! { #name_ident }), TypeKind::TemplateInstantiation(ref inst) => { if inst.is_opaque(ctx, self) { - Some((format!("{}: opaque", name), vec![])) + Some((format!("{name}: opaque"), vec![])) } else { - debug_print(name, quote! { #name_ident }) + debug_print(name, "e! { #name_ident }) } } // The generic is not required to implement Debug, so we can not debug print that type TypeKind::TypeParam => { - Some((format!("{}: Non-debuggable generic", name), vec![])) + Some((format!("{name}: Non-debuggable generic"), vec![])) } TypeKind::Array(_, len) => { // Generics are not required to implement Debug if self.has_type_param_in_array(ctx) { - Some(( - format!("{}: Array with length {}", name, len), - vec![], - )) - } else if len < RUST_DERIVE_IN_ARRAY_LIMIT || - ctx.options().rust_features().larger_arrays - { - // The simple case - debug_print(name, quote! { #name_ident }) - } else if ctx.options().use_core { - // There is no String in core; reducing field visibility to avoid breaking - // no_std setups. - Some((format!("{}: [...]", name), vec![])) + Some((format!("{name}: Array with length {len}"), vec![])) } else { - // Let's implement our own print function - Some(( - format!("{}: [{{}}]", name), - vec![quote! { - self.#name_ident - .iter() - .enumerate() - .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v)) - .collect::() - }], - )) + // The simple case + debug_print(name, "e! { #name_ident }) } } TypeKind::Vector(_, len) => { if ctx.options().use_core { // There is no format! in core; reducing field visibility to avoid breaking // no_std setups. - Some((format!("{}(...)", name), vec![])) + Some((format!("{name}(...)"), vec![])) } else { let self_ids = 0..len; Some(( - format!("{}({{}})", name), + format!("{name}({{}})"), vec![quote! { #(format!("{:?}", self.#self_ids)),* }], @@ -233,9 +208,9 @@ TypeKind::Function(ref sig) if !sig.function_pointers_can_derive() => { - Some((format!("{}: FunctionPointer", name), vec![])) + Some((format!("{name}: FunctionPointer"), vec![])) } - _ => debug_print(name, quote! { #name_ident }), + _ => debug_print(name, "e! { #name_ident }), } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/impl_partialeq.rs firefox-140.10.2/third_party/rust/bindgen/codegen/impl_partialeq.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/impl_partialeq.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/impl_partialeq.rs Mon May 11 04:49:32 2026 @@ -1,7 +1,7 @@ use crate::ir::comp::{CompInfo, CompKind, Field, FieldMethods}; use crate::ir::context::BindgenContext; use crate::ir::item::{IsOpaque, Item}; -use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; +use crate::ir::ty::TypeKind; /// Generate a manual implementation of `PartialEq` trait for the /// specified compound type. @@ -23,22 +23,14 @@ &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); } else { - for base in comp_info.base_members().iter() { + for base in comp_info.base_members() { if !base.requires_storage(ctx) { continue; } let ty_item = ctx.resolve_item(base.ty); let field_name = &base.field_name; - - if ty_item.is_opaque(ctx, &()) { - let field_name = ctx.rust_ident(field_name); - tokens.push(quote! { - &self. #field_name [..] == &other. #field_name [..] - }); - } else { - tokens.push(gen_field(ctx, ty_item, field_name)); - } + tokens.push(gen_field(ctx, ty_item, field_name)); } for field in comp_info.fields() { @@ -76,7 +68,7 @@ name: &str, ) -> proc_macro2::TokenStream { fn quote_equals( - name_ident: proc_macro2::Ident, + name_ident: &proc_macro2::Ident, ) -> proc_macro2::TokenStream { quote! { self.#name_ident == other.#name_ident } } @@ -100,29 +92,9 @@ TypeKind::Comp(..) | TypeKind::Pointer(_) | TypeKind::Function(..) | - TypeKind::Opaque => quote_equals(name_ident), - - TypeKind::TemplateInstantiation(ref inst) => { - if inst.is_opaque(ctx, ty_item) { - quote! { - &self. #name_ident [..] == &other. #name_ident [..] - } - } else { - quote_equals(name_ident) - } - } - - TypeKind::Array(_, len) => { - if len <= RUST_DERIVE_IN_ARRAY_LIMIT || - ctx.options().rust_features().larger_arrays - { - quote_equals(name_ident) - } else { - quote! { - &self. #name_ident [..] == &other. #name_ident [..] - } - } - } + TypeKind::Array(..) | + TypeKind::TemplateInstantiation(..) | + TypeKind::Opaque => quote_equals(&name_ident), TypeKind::Vector(_, len) => { let self_ids = 0..len; let other_ids = 0..len; diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/mod.rs firefox-140.10.2/third_party/rust/bindgen/codegen/mod.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/mod.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/mod.rs Mon May 11 04:49:32 2026 @@ -20,7 +20,10 @@ use super::BindgenOptions; -use crate::callbacks::{DeriveInfo, FieldInfo, TypeKind as DeriveTypeKind}; +use crate::callbacks::{ + AttributeInfo, DeriveInfo, DiscoveredItem, DiscoveredItemId, FieldInfo, + TypeKind as DeriveTypeKind, +}; use crate::codegen::error::Error; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::{ @@ -52,8 +55,8 @@ use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; -use proc_macro2::{self, Ident, Span}; -use quote::TokenStreamExt; +use proc_macro2::{Ident, Span}; +use quote::{ToTokens, TokenStreamExt}; use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; @@ -80,7 +83,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Serialize { msg, loc } => { - write!(f, "serialization error at {}: {}", loc, msg) + write!(f, "serialization error at {loc}: {msg}") } Self::Io(err) => err.fmt(f), } @@ -149,22 +152,16 @@ ) -> DerivableTraits { let mut derivable_traits = DerivableTraits::empty(); - let all_template_params = item.all_template_params(ctx); - if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derivable_traits |= DerivableTraits::COPY; - if ctx.options().rust_features().builtin_clone_impls || - !all_template_params.is_empty() - { - // FIXME: This requires extra logic if you have a big array in a - // templated struct. The reason for this is that the magic: - // fn clone(&self) -> Self { *self } - // doesn't work for templates. - // - // It's not hard to fix though. - derivable_traits |= DerivableTraits::CLONE; - } + // FIXME: This requires extra logic if you have a big array in a + // templated struct. The reason for this is that the magic: + // fn clone(&self) -> Self { *self } + // doesn't work for templates. + // + // It's not hard to fix though. + derivable_traits |= DerivableTraits::CLONE; } else if packed { // If the struct or union is packed, deriving from Copy is required for // deriving from any other trait. @@ -376,7 +373,7 @@ } } -impl<'a> ops::Deref for CodegenResult<'a> { +impl ops::Deref for CodegenResult<'_> { type Target = Vec; fn deref(&self) -> &Self::Target { @@ -384,7 +381,7 @@ } } -impl<'a> ops::DerefMut for CodegenResult<'a> { +impl ops::DerefMut for CodegenResult<'_> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items } @@ -497,8 +494,7 @@ if self.is_blocklisted(ctx) || result.seen(self.id()) { debug!( "::process_before_codegen: Ignoring hidden or seen: \ - self = {:?}", - self + self = {self:?}" ); return false; } @@ -507,7 +503,7 @@ // TODO(emilio, #453): Figure out what to do when this happens // legitimately, we could track the opaque stuff and disable the // assertion there I guess. - warn!("Found non-allowlisted item in code generation: {:?}", self); + warn!("Found non-allowlisted item in code generation: {self:?}"); } result.set_seen(self.id()); @@ -525,7 +521,7 @@ result: &mut CodegenResult<'_>, _extra: &(), ) { - debug!("::codegen: self = {:?}", self); + debug!("::codegen: self = {self:?}"); if !self.process_before_codegen(ctx, result) { return; } @@ -557,7 +553,7 @@ result: &mut CodegenResult<'_>, item: &Item, ) { - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); let codegen_self = |result: &mut CodegenResult, found_any: &mut bool| { @@ -584,6 +580,7 @@ if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } + utils::prepend_opaque_array_types(ctx, &mut *result); if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } @@ -656,7 +653,7 @@ item: &Item, ) { use crate::ir::var::VarType; - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); let canonical_name = item.canonical_name(ctx); @@ -677,7 +674,7 @@ let mut attrs = vec![]; if let Some(comment) = item.comment(ctx) { - attrs.push(attributes::doc(comment)); + attrs.push(attributes::doc(&comment)); } let var_ty = self.ty(); @@ -721,33 +718,40 @@ let len = proc_macro2::Literal::usize_unsuffixed( cstr_bytes.len(), ); - - // TODO: Here we ignore the type we just made up, probably - // we should refactor how the variable type and ty ID work. - let array_ty = quote! { [u8; #len] }; - let cstr_ty = quote! { ::#prefix::ffi::CStr }; - - let bytes = proc_macro2::Literal::byte_string(&cstr_bytes); - - if options.generate_cstr && - rust_features.const_cstr && - CStr::from_bytes_with_nul(&cstr_bytes).is_ok() - { - result.push(quote! { - #(#attrs)* - #[allow(unsafe_code)] - pub const #canonical_ident: &#cstr_ty = unsafe { - #cstr_ty::from_bytes_with_nul_unchecked(#bytes) - }; - }); - } else { - let lifetime = if rust_features.static_lifetime_elision - { + let cstr = + if options.generate_cstr && rust_features.const_cstr { + CStr::from_bytes_with_nul(&cstr_bytes).ok() + } else { None + }; + if let Some(cstr) = cstr { + let cstr_ty = quote! { ::#prefix::ffi::CStr }; + if rust_features.literal_cstr { + let cstr = proc_macro2::Literal::c_string(cstr); + result.push(quote! { + #(#attrs)* + pub const #canonical_ident: &#cstr_ty = #cstr; + }); } else { - Some(quote! { 'static }) + let bytes = + proc_macro2::Literal::byte_string(&cstr_bytes); + result.push(quote! { + #(#attrs)* + #[allow(unsafe_code)] + pub const #canonical_ident: &#cstr_ty = unsafe { + #cstr_ty::from_bytes_with_nul_unchecked(#bytes) + }; + }); } - .into_iter(); + } else { + // TODO: Here we ignore the type we just made up, probably + // we should refactor how the variable type and ty ID work. + let array_ty = quote! { [u8; #len] }; + let bytes = + proc_macro2::Literal::byte_string(&cstr_bytes); + let lifetime = + if true { None } else { Some(quote! { 'static }) } + .into_iter(); result.push(quote! { #(#attrs)* @@ -756,7 +760,7 @@ } } VarType::Float(f) => { - if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) { + if let Ok(expr) = helpers::ast_ty::float_expr(f) { result.push(quote! { #(#attrs)* pub const #canonical_ident : #ty = #expr ; @@ -771,20 +775,20 @@ } } } else { - // If necessary, apply a `#[link_name]` attribute - if let Some(link_name) = self.link_name() { - attrs.push(attributes::link_name::(link_name)); - } else { + let symbol: &str = self.link_name().unwrap_or_else(|| { let link_name = self.mangled_name().unwrap_or_else(|| self.name()); - if !utils::names_will_be_identical_after_mangling( + if utils::names_will_be_identical_after_mangling( &canonical_name, link_name, None, ) { + canonical_name.as_str() + } else { attrs.push(attributes::link_name::(link_name)); + link_name } - } + }); let maybe_mut = if self.is_const() { quote! {} @@ -792,14 +796,33 @@ quote! { mut } }; + let safety = ctx + .options() + .rust_features + .unsafe_extern_blocks + .then(|| quote!(unsafe)); + let tokens = quote!( - extern "C" { + #safety extern "C" { #(#attrs)* pub static #maybe_mut #canonical_ident: #ty; } ); - result.push(tokens); + if ctx.options().dynamic_library_name.is_some() { + result.dynamic_items().push_var( + &canonical_ident, + symbol, + &self + .ty() + .to_rust_ty_or_opaque(ctx, &()) + .into_token_stream(), + ctx.options().dynamic_link_require_all, + ctx.options().wrap_unsafe_ops, + ); + } else { + result.push(tokens); + } } } } @@ -814,7 +837,7 @@ result: &mut CodegenResult<'_>, item: &Item, ) { - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); match *self.kind() { @@ -837,7 +860,7 @@ // it to BindgenContext::compute_allowlisted_and_codegen_items. } TypeKind::TemplateInstantiation(ref inst) => { - inst.codegen(ctx, result, item) + inst.codegen(ctx, result, item); } TypeKind::BlockPointer(inner) => { if !ctx.options().generate_block { @@ -854,14 +877,14 @@ { utils::fnsig_block(ctx, fnsig) } else { - panic!("invalid block typedef: {:?}", inner_item) + panic!("invalid block typedef: {inner_item:?}") } }; let rust_name = ctx.rust_ident(name); let mut tokens = if let Some(comment) = item.comment(ctx) { - attributes::doc(comment) + attributes::doc(&comment) } else { quote! {} }; @@ -912,16 +935,14 @@ 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, + "Target platform requires `--no-size_t-is-usize`. The size of `{spelling}` ({}) does not match the target pointer size ({})", layout.size, ctx.target_pointer_size(), ); assert_eq!( layout.align, ctx.target_pointer_size(), - "Target platform requires `--no-size_t-is-usize`. The alignment of `{}` ({}) does not match the target pointer size ({})", - spelling, + "Target platform requires `--no-size_t-is-usize`. The alignment of `{spelling}` ({}) does not match the target pointer size ({})", layout.align, ctx.target_pointer_size(), ); @@ -961,8 +982,7 @@ if inner_canon_type.is_invalid_type_param() { warn!( "Item contained invalid named type, skipping: \ - {:?}, {:?}", - item, inner_item + {item:?}, {inner_item:?}" ); return; } @@ -970,8 +990,17 @@ let rust_name = ctx.rust_ident(&name); + utils::call_discovered_item_callback(ctx, item, || { + DiscoveredItem::Alias { + alias_name: rust_name.to_string(), + alias_for: DiscoveredItemId::new( + inner_item.id().as_usize(), + ), + } + }); + let mut tokens = if let Some(comment) = item.comment(ctx) { - attributes::doc(comment) + attributes::doc(&comment) } else { quote! {} }; @@ -1011,22 +1040,39 @@ pub type #rust_name }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { - assert!( - ctx.options().rust_features().repr_transparent, - "repr_transparent feature is required to use {:?}", - alias_style - ); - let mut attributes = vec![attributes::repr("transparent")]; let packed = false; // Types can't be packed in Rust. let derivable_traits = derives_of_item(item, ctx, packed); - if !derivable_traits.is_empty() { - let derives: Vec<_> = derivable_traits.into(); - attributes.push(attributes::derives(&derives)) - } + let mut derives: Vec<_> = derivable_traits.into(); + // The custom derives callback may return a list of derive attributes; + // add them to the end of the list. + let custom_derives = + ctx.options().all_callbacks(|cb| { + cb.add_derives(&DeriveInfo { + name: &name, + kind: DeriveTypeKind::Struct, + }) + }); + // In most cases this will be a no-op, since custom_derives will be empty. + derives + .extend(custom_derives.iter().map(|s| s.as_str())); + attributes.push(attributes::derives(&derives)); + let custom_attributes = + ctx.options().all_callbacks(|cb| { + cb.add_attributes(&AttributeInfo { + name: &name, + kind: DeriveTypeKind::Struct, + }) + }); + attributes.extend( + custom_attributes + .iter() + .map(|s| s.parse().unwrap()), + ); + quote! { #( #attributes )* pub struct #rust_name @@ -1044,8 +1090,7 @@ { warn!( "Item contained invalid template \ - parameter: {:?}", - item + parameter: {item:?}" ); return; } @@ -1064,13 +1109,24 @@ }); } - let access_spec = - access_specifier(ctx.options().default_visibility); tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { = #inner_rust_type ; }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { + let visibility = ctx + .options() + .last_callback(|cb| { + cb.field_visibility(FieldInfo { + type_name: &item.canonical_name(ctx), + field_name: "0", + field_type_name: inner_item + .expect_type() + .name(), + }) + }) + .unwrap_or(ctx.options().default_visibility); + let access_spec = access_specifier(visibility); quote! { (#access_spec #inner_rust_type) ; } @@ -1103,10 +1159,10 @@ result.saw_objc(); } TypeKind::ObjCInterface(ref interface) => { - interface.codegen(ctx, result, item) + interface.codegen(ctx, result, item); } ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) + unreachable!("Should have been resolved after parsing {u:?}!") } } } @@ -1125,7 +1181,7 @@ } } -impl<'a> CodeGenerator for Vtable<'a> { +impl CodeGenerator for Vtable<'_> { type Extra = Item; type Return = (); @@ -1160,10 +1216,7 @@ 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"), - }; + let TypeKind::Function(ref signature) = signature_item.expect_type().kind() else { panic!("Function signature type mismatch") }; // FIXME: Is there a canonical name without the class prepended? let function_name = function_item.canonical_name(ctx); @@ -1190,7 +1243,7 @@ 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); @@ -1203,13 +1256,13 @@ } } -impl<'a> ItemCanonicalName for Vtable<'a> { +impl ItemCanonicalName for Vtable<'_> { fn canonical_name(&self, ctx: &BindgenContext) -> String { format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) } } -impl<'a> TryToRustTy for Vtable<'a> { +impl TryToRustTy for Vtable<'_> { type Extra = (); fn try_to_rust_ty( @@ -1244,6 +1297,9 @@ return; } + // For consistency with other layout tests, gate this on offset_of. + let compile_time = ctx.options().rust_features().offset_of; + // If there are any unbound type parameters, then we can't generate a // layout test because we aren't dealing with a concrete type with a // concrete size and alignment. @@ -1258,15 +1314,18 @@ let align = layout.align; let name = item.full_disambiguated_name(ctx); - let mut fn_name = - format!("__bindgen_test_layout_{}_instantiation", name); - let times_seen = result.overload_number(&fn_name); - if times_seen > 0 { - write!(&mut fn_name, "_{}", times_seen).unwrap(); - } + let fn_name = if compile_time { + None + } else { + let mut fn_name = + format!("__bindgen_test_layout_{name}_instantiation"); + let times_seen = result.overload_number(&fn_name); + if times_seen > 0 { + write!(&mut fn_name, "_{times_seen}").unwrap(); + } + Some(ctx.rust_ident_raw(fn_name)) + }; - let fn_name = ctx.rust_ident_raw(fn_name); - let prefix = ctx.trait_prefix(); let ident = item.to_rust_ty_or_opaque(ctx, &()); let size_of_expr = quote! { @@ -1275,20 +1334,33 @@ let align_of_expr = quote! { ::#prefix::mem::align_of::<#ident>() }; + let size_of_err = + format!("Size of template specialization: {name}"); + let align_of_err = + format!("Align of template specialization: {name}"); - let item = quote! { - #[test] - fn #fn_name() { - assert_eq!(#size_of_expr, #size, - concat!("Size of template specialization: ", - stringify!(#ident))); - assert_eq!(#align_of_expr, #align, - concat!("Alignment of template specialization: ", - stringify!(#ident))); - } - }; - - result.push(item); + if compile_time { + // In an ideal world this would be assert_eq!, but that is not + // supported in const fn due to the need for string formatting. + // If #size_of_expr > #size, this will index OOB, and if + // #size_of_expr < #size, the subtraction will overflow, both + // of which print enough information to see what has gone wrong. + result.push(quote! { + #[allow(clippy::unnecessary_operation, clippy::identity_op)] + const _: () = { + [#size_of_err][#size_of_expr - #size]; + [#align_of_err][#align_of_expr - #align]; + }; + }); + } else { + result.push(quote! { + #[test] + fn #fn_name() { + assert_eq!(#size_of_expr, #size, #size_of_err); + assert_eq!(#align_of_expr, #align, #align_of_err); + } + }); + } } } } @@ -1305,6 +1377,7 @@ accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1315,7 +1388,7 @@ M: Extend; } -impl<'a> FieldCodegen<'a> for Field { +impl FieldCodegen<'_> for Field { type Extra = (); fn codegen( @@ -1325,6 +1398,7 @@ accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1342,6 +1416,7 @@ accessor_kind, parent, parent_item, + last_field, result, struct_layout, fields, @@ -1356,6 +1431,7 @@ accessor_kind, parent, parent_item, + last_field, result, struct_layout, fields, @@ -1390,7 +1466,7 @@ } } -impl<'a> FieldCodegen<'a> for FieldData { +impl FieldCodegen<'_> for FieldData { type Extra = (); fn codegen( @@ -1400,6 +1476,7 @@ accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1425,14 +1502,20 @@ 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(); + // Only FAM if its the last field + if ctx.options().flexarray_dst && last_field { + struct_layout.saw_flexible_array(); + syn::parse_quote! { FAM } + } else { + result.saw_incomplete_array(); - let inner = item.to_rust_ty_or_opaque(ctx, &()); + let inner = item.to_rust_ty_or_opaque(ctx, &()); - if ctx.options().enable_cxx_namespaces { - syn::parse_quote! { root::__IncompleteArrayField<#inner> } - } else { - syn::parse_quote! { __IncompleteArrayField<#inner> } + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::__IncompleteArrayField<#inner> } + } else { + syn::parse_quote! { __IncompleteArrayField<#inner> } + } } } else { ty @@ -1442,7 +1525,7 @@ if ctx.options().generate_comments { if let Some(raw_comment) = self.comment() { let comment = ctx.options().process_comment(raw_comment); - field = attributes::doc(comment); + field = attributes::doc(&comment); } } @@ -1466,6 +1549,7 @@ cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, + field_type_name: field_ty.name(), }) }), self.annotations(), @@ -1499,9 +1583,9 @@ return; } - let getter_name = ctx.rust_ident_raw(format!("get_{}", field_name)); + let getter_name = ctx.rust_ident_raw(format!("get_{field_name}")); let mutable_getter_name = - ctx.rust_ident_raw(format!("get_{}_mut", field_name)); + ctx.rust_ident_raw(format!("get_{field_name}_mut")); methods.extend(Some(match accessor_kind { FieldAccessorKind::None => unreachable!(), @@ -1563,18 +1647,17 @@ fn extend_ctor_impl( &self, ctx: &BindgenContext, - param_name: proc_macro2::TokenStream, + param_name: &proc_macro2::TokenStream, mut ctor_impl: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { let bitfield_ty = ctx.resolve_type(self.ty()); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); - let bitfield_int_ty = helpers::integer_type(ctx, bitfield_ty_layout) - .expect( - "Should already have verified that the bitfield is \ + let bitfield_int_ty = helpers::integer_type(bitfield_ty_layout).expect( + "Should already have verified that the bitfield is \ representable as an int", - ); + ); let offset = self.offset_into_unit(); let width = self.width() as u8; @@ -1609,13 +1692,13 @@ /// Compute a fields or structs visibility based on multiple conditions. /// 1. If the element was declared public, and we respect such CXX accesses specs -/// (context option) => By default Public, but this can be overruled by an `annotation`. +/// (context option) => By default Public, but this can be overruled by an `annotation`. /// /// 2. If the element was declared private, and we respect such CXX accesses specs -/// (context option) => By default Private, but this can be overruled by an `annotation`. +/// (context option) => By default Private, but this can be overruled by an `annotation`. /// /// 3. If we do not respect visibility modifiers, the result depends on the `annotation`, -/// if any, or the passed `default_kind`. +/// if any, or the passed `default_kind`. /// fn compute_visibility( ctx: &BindgenContext, @@ -1644,7 +1727,7 @@ }) } -impl<'a> FieldCodegen<'a> for BitfieldUnit { +impl FieldCodegen<'_> for BitfieldUnit { type Extra = (); fn codegen( @@ -1654,6 +1737,7 @@ accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + last_field: bool, result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, fields: &mut F, @@ -1683,22 +1767,6 @@ } }; - { - let align_field_name = format!("_bitfield_align_{}", self.nth()); - let align_field_ident = ctx.rust_ident(align_field_name); - let align_ty = match self.layout().align { - n if n >= 8 => quote! { u64 }, - 4 => quote! { u32 }, - 2 => quote! { u16 }, - _ => quote! { u8 }, - }; - let access_spec = access_specifier(visibility_kind); - let align_field = quote! { - #access_spec #align_field_ident: [#align_ty; 0], - }; - fields.extend(Some(align_field)); - } - let unit_field_name = format!("_bitfield_{}", self.nth()); let unit_field_ident = ctx.rust_ident(&unit_field_name); @@ -1714,18 +1782,13 @@ let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; let mut unit_visibility = visibility_kind; - for bf in self.bitfields() { + let bfields = self.bitfields(); + for (idx, bf) in bfields.iter().enumerate() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { continue; } - if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT && - !ctx.options().rust_features().larger_arrays - { - continue; - } - let mut bitfield_representable_as_int = true; let mut bitfield_visibility = visibility_kind; bf.codegen( @@ -1734,12 +1797,14 @@ accessor_kind, parent, parent_item, + last_field && idx == bfields.len() - 1, result, struct_layout, fields, methods, ( &unit_field_name, + &unit_field_ty, &mut bitfield_representable_as_int, &mut bitfield_visibility, ), @@ -1763,7 +1828,7 @@ ctor_params.push(quote! { #param_name : #bitfield_ty }); - ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl); + ctor_impl = bf.extend_ctor_impl(ctx, ¶m_name, ctor_impl); } let access_spec = access_specifier(unit_visibility); @@ -1797,6 +1862,15 @@ quote! { #name } } +fn bitfield_raw_getter_name( + ctx: &BindgenContext, + bitfield: &Bitfield, +) -> proc_macro2::TokenStream { + let name = bitfield.getter_name(); + let name = ctx.rust_ident_raw(format!("{name}_raw")); + quote! { #name } +} + fn bitfield_setter_name( ctx: &BindgenContext, bitfield: &Bitfield, @@ -1806,8 +1880,22 @@ quote! { #setter } } +fn bitfield_raw_setter_name( + ctx: &BindgenContext, + bitfield: &Bitfield, +) -> proc_macro2::TokenStream { + let setter = bitfield.setter_name(); + let setter = ctx.rust_ident_raw(format!("{setter}_raw")); + quote! { #setter } +} + impl<'a> FieldCodegen<'a> for Bitfield { - type Extra = (&'a str, &'a mut bool, &'a mut FieldVisibilityKind); + type Extra = ( + &'a str, + &'a syn::Type, + &'a mut bool, + &'a mut FieldVisibilityKind, + ); fn codegen( &self, @@ -1816,12 +1904,19 @@ _accessor_kind: FieldAccessorKind, parent: &CompInfo, parent_item: &Item, + _last_field: bool, _result: &mut CodegenResult, struct_layout: &mut StructLayoutTracker, _fields: &mut F, methods: &mut M, - (unit_field_name, bitfield_representable_as_int, bitfield_visibility): ( + ( + unit_field_name, + unit_field_ty, + bitfield_representable_as_int, + bitfield_visibility, + ): ( &'a str, + &'a syn::Type, &mut bool, &'a mut FieldVisibilityKind, ), @@ -1832,24 +1927,24 @@ let prefix = ctx.trait_prefix(); let getter_name = bitfield_getter_name(ctx, self); let setter_name = bitfield_setter_name(ctx, self); + let raw_getter_name = bitfield_raw_getter_name(ctx, self); + let raw_setter_name = bitfield_raw_setter_name(ctx, self); let unit_field_ident = Ident::new(unit_field_name, Span::call_site()); let bitfield_ty_item = ctx.resolve_item(self.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); + let bitfield_ty_ident = bitfield_ty.name(); let bitfield_ty_layout = bitfield_ty .layout(ctx) .expect("Bitfield without layout? Gah!"); let bitfield_int_ty = - match helpers::integer_type(ctx, bitfield_ty_layout) { - Some(int_ty) => { - *bitfield_representable_as_int = true; - int_ty - } - None => { - *bitfield_representable_as_int = false; - return; - } + if let Some(int_ty) = helpers::integer_type(bitfield_ty_layout) { + *bitfield_representable_as_int = true; + int_ty + } else { + *bitfield_representable_as_int = false; + return; }; let bitfield_ty = @@ -1863,6 +1958,7 @@ cb.field_visibility(FieldInfo { type_name: &parent_item.canonical_name(ctx), field_name, + field_type_name: bitfield_ty_ident, }) }) }); @@ -1899,6 +1995,32 @@ } } })); + + methods.extend(Some(quote! { + #[inline] + #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { + unsafe { + ::#prefix::mem::transmute(<#unit_field_ty>::raw_get( + (*::#prefix::ptr::addr_of!((*this).#unit_field_ident)).as_ref() as *const _, + #offset, + #width, + ) as #bitfield_int_ty) + } + } + + #[inline] + #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { + unsafe { + let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); + <#unit_field_ty>::raw_set( + (*::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident)).as_mut() as *mut _, + #offset, + #width, + val as u64, + ) + } + } + })); } else { methods.extend(Some(quote! { #[inline] @@ -1923,6 +2045,32 @@ } } })); + + methods.extend(Some(quote! { + #[inline] + #access_spec unsafe fn #raw_getter_name(this: *const Self) -> #bitfield_ty { + unsafe { + ::#prefix::mem::transmute(<#unit_field_ty>::raw_get( + ::#prefix::ptr::addr_of!((*this).#unit_field_ident), + #offset, + #width, + ) as #bitfield_int_ty) + } + } + + #[inline] + #access_spec unsafe fn #raw_setter_name(this: *mut Self, val: #bitfield_ty) { + unsafe { + let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); + <#unit_field_ty>::raw_set( + ::#prefix::ptr::addr_of_mut!((*this).#unit_field_ident), + #offset, + #width, + val as u64, + ) + } + } + })); } } } @@ -1937,7 +2085,7 @@ result: &mut CodegenResult<'_>, item: &Item, ) { - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); // Don't output classes with template parameters that aren't types, and @@ -1980,6 +2128,23 @@ packed, ); + let mut generic_param_names = vec![]; + + for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { + let param = ctx.resolve_type(*ty); + let name = param.name().unwrap(); + let ident = ctx.rust_ident(name); + generic_param_names.push(ident.clone()); + + let prefix = ctx.trait_prefix(); + let field_name = ctx.rust_ident(format!("_phantom_{idx}")); + fields.push(quote! { + pub #field_name : ::#prefix::marker::PhantomData< + ::#prefix::cell::UnsafeCell<#ident> + > , + }); + } + if !is_opaque { if item.has_vtable_ptr(ctx) { let vtable = Vtable::new(item.id(), self); @@ -2032,13 +2197,15 @@ .annotations() .accessor_kind() .unwrap_or(FieldAccessorKind::None); - for field in self.fields() { + let field_decls = self.fields(); + for (idx, field) in field_decls.iter().enumerate() { field.codegen( ctx, visibility, struct_accessor_kind, self, item, + idx == field_decls.len() - 1, result, &mut struct_layout, &mut fields, @@ -2090,14 +2257,13 @@ if has_address { let layout = Layout::new(1, 1); - let ty = helpers::blob(ctx, Layout::new(1, 1)); struct_layout.saw_field_with_layout( "_address", layout, /* offset = */ Some(0), ); fields.push(quote! { - pub _address: #ty, + pub _address: u8, }); } } @@ -2106,14 +2272,15 @@ match layout { Some(l) => { explicit_align = Some(l.align); - - let ty = helpers::blob(ctx, l); + let ty = helpers::blob(ctx, l, false); fields.push(quote! { pub _bindgen_opaque_blob: #ty , }); } None => { - warn!("Opaque type without layout! Expect dragons!"); + if !forward_decl { + warn!("Opaque type without layout! Expect dragons!"); + } } } } else if !is_union && !zero_sized { @@ -2129,32 +2296,22 @@ packed = true; } else { explicit_align = Some(layout.align); - if !ctx.options().rust_features.repr_align { - let ty = helpers::blob( - ctx, - Layout::new(0, layout.align), - ); - fields.push(quote! { - pub __bindgen_align: #ty , - }); - } } } } } else if is_union && !forward_decl { - // TODO(emilio): It'd be nice to unify this with the struct path - // above somehow. - let layout = layout.expect("Unable to get layout information?"); - if struct_layout.requires_explicit_align(layout) { - explicit_align = Some(layout.align); + if let Some(layout) = layout { + // TODO(emilio): It'd be nice to unify this with the struct path above somehow. + if struct_layout.requires_explicit_align(layout) { + explicit_align = Some(layout.align); + } + if !struct_layout.is_rust_union() { + let ty = helpers::blob(ctx, layout, false); + fields.push(quote! { + pub bindgen_union_field: #ty, + }); + } } - - if !struct_layout.is_rust_union() { - let ty = helpers::blob(ctx, layout); - fields.push(quote! { - pub bindgen_union_field: #ty , - }) - } } if forward_decl { @@ -2163,39 +2320,62 @@ }); } - let mut generic_param_names = vec![]; - - for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { - let param = ctx.resolve_type(*ty); - let name = param.name().unwrap(); - let ident = ctx.rust_ident(name); - generic_param_names.push(ident.clone()); - - let prefix = ctx.trait_prefix(); - let field_name = ctx.rust_ident(format!("_phantom_{}", idx)); - fields.push(quote! { - pub #field_name : ::#prefix::marker::PhantomData< - ::#prefix::cell::UnsafeCell<#ident> - > , - }); - } - - let generics = if !generic_param_names.is_empty() { - let generic_param_names = generic_param_names.clone(); - quote! { - < #( #generic_param_names ),* > + let (flex_array_generic, flex_inner_ty) = if ctx.options().flexarray_dst + { + match self.flex_array_member(ctx) { + Some(ty) => { + let inner = ty.to_rust_ty_or_opaque(ctx, &()); + ( + Some(quote! { FAM: ?Sized = [ #inner; 0 ] }), + Some(quote! { #inner }), + ) + } + None => (None, None), } } else { - quote! {} + (None, None) }; + // Generics, including the flexible array member. + // + // generics - generic parameters for the struct declaration + // impl_generics_labels - generic parameters for `impl<...>` + // impl_generics_params - generic parameters for `impl structname<...>` + // + // `impl` blocks are for non-FAM related impls like Default, etc + let (generics, impl_generics_labels, impl_generics_params) = + if !generic_param_names.is_empty() || flex_array_generic.is_some() { + let (flex_sized, flex_fam) = match flex_inner_ty.as_ref() { + None => (None, None), + Some(ty) => ( + Some(quote! { [ #ty; 0 ] }), + Some(quote! { FAM: ?Sized = [ #ty; 0 ] }), + ), + }; + + ( + quote! { + < #( #generic_param_names , )* #flex_fam > + }, + quote! { + < #( #generic_param_names , )* > + }, + quote! { + < #( #generic_param_names , )* #flex_sized > + }, + ) + } else { + (quote! {}, quote! {}, quote! {}) + }; + let mut attributes = vec![]; let mut needs_clone_impl = false; let mut needs_default_impl = false; let mut needs_debug_impl = false; let mut needs_partialeq_impl = false; + let needs_flexarray_impl = flex_array_generic.is_some(); if let Some(comment) = item.comment(ctx) { - attributes.push(attributes::doc(comment)); + attributes.push(attributes::doc(&comment)); } // if a type has both a "packed" attribute and an "align(N)" attribute, then check if the @@ -2206,21 +2386,34 @@ self.already_packed(ctx).unwrap_or(false)) { let n = layout.map_or(1, |l| l.align); - assert!(ctx.options().rust_features().repr_packed_n || n == 1); let packed_repr = if n == 1 { "packed".to_string() } else { - format!("packed({})", n) + format!("packed({n})") }; attributes.push(attributes::repr_list(&["C", &packed_repr])); } else { attributes.push(attributes::repr("C")); } - if ctx.options().rust_features().repr_align { - if let Some(explicit) = explicit_align { - // Ensure that the struct has the correct alignment even in - // presence of alignas. + // Ensure that the struct has the correct alignment even in presence of alignas and co. + if let Some(explicit) = explicit_align { + // If we need explicit alignment and can do it, we prefer to insert a dummy field at + // the beginning of the struct. This avoids hitting + // https://github.com/rust-lang/rust-bindgen/issues/2179 + // Do it for bitfields only for now for backwards compat. + if self.has_bitfields() && explicit <= 8 { + let align_ty = match explicit { + 8 => quote! { u64 }, + 4 => quote! { u32 }, + 2 => quote! { u16 }, + _ => quote! { u8 }, + }; + let align_field = quote! { + pub _bindgen_align: [#align_ty; 0], + }; + fields.insert(0, align_field); + } else { let explicit = helpers::ast_ty::int_expr(explicit as i64); attributes.push(quote! { #[repr(align(#explicit))] @@ -2263,6 +2456,25 @@ let is_rust_union = is_union && struct_layout.is_rust_union(); + utils::call_discovered_item_callback(ctx, item, || match self.kind() { + CompKind::Struct => DiscoveredItem::Struct { + original_name: item + .kind() + .expect_type() + .name() + .map(String::from), + final_name: canonical_ident.to_string(), + }, + CompKind::Union => DiscoveredItem::Union { + original_name: item + .kind() + .expect_type() + .name() + .map(String::from), + final_name: canonical_ident.to_string(), + }, + }); + // The custom derives callback may return a list of derive attributes; // add them to the end of the list. let custom_derives = ctx.options().all_callbacks(|cb| { @@ -2279,9 +2491,28 @@ derives.extend(custom_derives.iter().map(|s| s.as_str())); if !derives.is_empty() { - attributes.push(attributes::derives(&derives)) + attributes.push(attributes::derives(&derives)); } + attributes.extend( + item.annotations() + .attributes() + .iter() + .map(|s| s.parse().unwrap()), + ); + + let custom_attributes = ctx.options().all_callbacks(|cb| { + cb.add_attributes(&AttributeInfo { + name: &canonical_name, + kind: if is_rust_union { + DeriveTypeKind::Union + } else { + DeriveTypeKind::Struct + }, + }) + }); + attributes.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); + if item.must_use(ctx) { attributes.push(attributes::must_use()); } @@ -2319,10 +2550,7 @@ // affect layout, so we're bad and pray to the gods for avoid sending // all the tests to shit when parsing things like max_align_t. if self.found_unknown_attr() { - warn!( - "Type {} has an unknown attribute that may affect layout", - canonical_ident - ); + warn!("Type {canonical_ident} has an unknown attribute that may affect layout"); } if all_template_params.is_empty() { @@ -2334,9 +2562,14 @@ if ctx.options().layout_tests && !self.is_forward_declaration() { if let Some(layout) = layout { - let fn_name = - format!("bindgen_test_layout_{}", canonical_ident); - let fn_name = ctx.rust_ident_raw(fn_name); + let compile_time = ctx.options().rust_features().offset_of; + let fn_name = if compile_time { + None + } else { + let fn_name = + format!("bindgen_test_layout_{canonical_ident}"); + Some(ctx.rust_ident_raw(fn_name)) + }; let prefix = ctx.trait_prefix(); let size_of_expr = quote! { ::#prefix::mem::size_of::<#canonical_ident>() @@ -2346,19 +2579,18 @@ }; let size = layout.size; let align = layout.align; + let size_of_err = format!("Size of {canonical_ident}"); + let align_of_err = + format!("Alignment of {canonical_ident}"); - let check_struct_align = if align > - ctx.target_pointer_size() && - !ctx.options().rust_features().repr_align - { - None + let check_struct_align = if compile_time { + quote! { + [#align_of_err][#align_of_expr - #align]; + } } else { - Some(quote! { - assert_eq!(#align_of_expr, - #align, - concat!("Alignment of ", stringify!(#canonical_ident))); - - }) + quote! { + assert_eq!(#align_of_expr, #align, #align_of_err); + } }; let should_skip_field_offset_checks = is_opaque; @@ -2369,30 +2601,40 @@ } else { self.fields() .iter() - .filter_map(|field| match *field { - Field::DataMember(ref f) if f.name().is_some() => Some(f), - _ => None, - }) - .flat_map(|field| { - let name = field.name().unwrap(); + .filter_map(|field| { + let Field::DataMember(field) = field else { return None }; + let name = field.name()?; 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)) - ); + let offset_of_err = format!("Offset of field: {canonical_ident}::{field_name}"); + if compile_time { + quote! { + [#offset_of_err][ + ::#prefix::mem::offset_of!(#canonical_ident, #field_name) - #field_offset + ]; + } + } else { + quote! { + assert_eq!( + unsafe { + ::#prefix::ptr::addr_of!((*ptr).#field_name) as usize - ptr as usize + }, + #field_offset, + #offset_of_err + ); + } } }) }) .collect() }; - let uninit_decl = if !check_field_offset.is_empty() { + let uninit_decl = if check_field_offset.is_empty() || + compile_time + { + None + } else { // FIXME: When MSRV >= 1.59.0, we can use // > const PTR: *const #canonical_ident = ::#prefix::mem::MaybeUninit::uninit().as_ptr(); Some(quote! { @@ -2402,35 +2644,43 @@ const UNINIT: ::#prefix::mem::MaybeUninit<#canonical_ident> = ::#prefix::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); }) - } else { - None }; - let item = quote! { - #[test] - fn #fn_name() { - #uninit_decl - assert_eq!(#size_of_expr, - #size, - concat!("Size of: ", stringify!(#canonical_ident))); - #check_struct_align - #( #check_field_offset )* - } - }; - result.push(item); + if compile_time { + result.push(quote! { + #[allow(clippy::unnecessary_operation, clippy::identity_op)] + const _: () = { + [#size_of_err][#size_of_expr - #size]; + #check_struct_align + #( #check_field_offset )* + }; + }); + } else { + result.push(quote! { + #[test] + fn #fn_name() { + #uninit_decl + assert_eq!(#size_of_expr, #size, #size_of_err); + #check_struct_align + #( #check_field_offset )* + } + }); + } } } let mut method_names = Default::default(); + let discovered_id = DiscoveredItemId::new(item.id().as_usize()); if ctx.options().codegen_config.methods() { for method in self.methods() { - assert!(method.kind() != MethodKind::Constructor); + assert_ne!(method.kind(), MethodKind::Constructor); method.codegen_method( ctx, &mut methods, &mut method_names, result, self, + discovered_id, ); } } @@ -2449,6 +2699,7 @@ &mut method_names, result, self, + discovered_id, ); } } @@ -2462,6 +2713,7 @@ &mut method_names, result, self, + discovered_id, ); } } @@ -2470,42 +2722,42 @@ // NB: We can't use to_rust_ty here since for opaque types this tries to // use the specialization knowledge to generate a blob field. let ty_for_impl = quote! { - #canonical_ident #generics + #canonical_ident #impl_generics_params }; if needs_clone_impl { result.push(quote! { - impl #generics Clone for #ty_for_impl { + impl #impl_generics_labels Clone for #ty_for_impl { fn clone(&self) -> Self { *self } } }); } + if needs_flexarray_impl { + result.push(self.generate_flexarray( + ctx, + &canonical_ident, + flex_inner_ty.as_ref(), + &generic_param_names, + &impl_generics_labels, + )); + } + if needs_default_impl { let prefix = ctx.trait_prefix(); - let body = if ctx.options().rust_features().maybe_uninit { - quote! { - let mut s = ::#prefix::mem::MaybeUninit::::uninit(); - unsafe { - ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } + let body = quote! { + let mut s = ::#prefix::mem::MaybeUninit::::uninit(); + unsafe { + ::#prefix::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() } - } else { - quote! { - unsafe { - let mut s: Self = ::#prefix::mem::uninitialized(); - ::#prefix::ptr::write_bytes(&mut s, 0, 1); - s - } - } }; // Note we use `ptr::write_bytes()` instead of `mem::zeroed()` because the latter does // not necessarily ensure padding bytes are zeroed. Some C libraries are sensitive to - // non-zero padding bytes, especially when forwards/backwards compatability is + // non-zero padding bytes, especially when forwards/backwards compatibility is // involved. result.push(quote! { - impl #generics Default for #ty_for_impl { + impl #impl_generics_labels Default for #ty_for_impl { fn default() -> Self { #body } @@ -2524,7 +2776,7 @@ let prefix = ctx.trait_prefix(); result.push(quote! { - impl #generics ::#prefix::fmt::Debug for #ty_for_impl { + impl #impl_generics_labels ::#prefix::fmt::Debug for #ty_for_impl { #impl_ } }); @@ -2537,18 +2789,18 @@ item, &ty_for_impl, ) { - let partialeq_bounds = if !generic_param_names.is_empty() { + let partialeq_bounds = if generic_param_names.is_empty() { + quote! {} + } else { let bounds = generic_param_names.iter().map(|t| { quote! { #t: PartialEq } }); quote! { where #( #bounds ),* } - } else { - quote! {} }; let prefix = ctx.trait_prefix(); result.push(quote! { - impl #generics ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { + impl #impl_generics_labels ::#prefix::cmp::PartialEq for #ty_for_impl #partialeq_bounds { #impl_ } }); @@ -2557,7 +2809,7 @@ if !methods.is_empty() { result.push(quote! { - impl #generics #ty_for_impl { + impl #impl_generics_labels #ty_for_impl { #( #methods )* } }); @@ -2565,6 +2817,142 @@ } } +impl CompInfo { + fn generate_flexarray( + &self, + ctx: &BindgenContext, + canonical_ident: &Ident, + flex_inner_ty: Option<&proc_macro2::TokenStream>, + generic_param_names: &[Ident], + impl_generics_labels: &proc_macro2::TokenStream, + ) -> proc_macro2::TokenStream { + let prefix = ctx.trait_prefix(); + + let flex_array = flex_inner_ty.as_ref().map(|ty| quote! { [ #ty ] }); + + let dst_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* #flex_array > + + }; + let sized_ty_for_impl = quote! { + #canonical_ident < #( #generic_param_names , )* [ #flex_inner_ty; 0 ] > + }; + + let layout = if ctx.options().rust_features().layout_for_ptr { + quote! { + pub fn layout(len: usize) -> ::#prefix::alloc::Layout { + // SAFETY: Null pointers are OK if we don't deref them + unsafe { + let p: *const Self = ::#prefix::ptr::from_raw_parts(::#prefix::ptr::null::<()>(), len); + ::#prefix::alloc::Layout::for_value_raw(p) + } + } + } + } else { + quote!() + }; + + let (from_ptr_dst, from_ptr_sized) = if ctx + .options() + .rust_features() + .ptr_metadata + { + let flex_ref_inner = ctx.wrap_unsafe_ops(quote! { + Self::flex_ptr(self, len) + }); + let flex_ref_mut_inner = ctx.wrap_unsafe_ops(quote! { + Self::flex_ptr_mut(self, len).assume_init() + }); + let flex_ptr_inner = ctx.wrap_unsafe_ops(quote! { + &*::#prefix::ptr::from_raw_parts(ptr as *const (), len) + }); + let flex_ptr_mut_inner = ctx.wrap_unsafe_ops(quote! { + // Initialize reference without ever exposing it, as its possibly uninitialized + let mut uninit = ::#prefix::mem::MaybeUninit::<&mut #dst_ty_for_impl>::uninit(); + (uninit.as_mut_ptr() as *mut *mut #dst_ty_for_impl) + .write(::#prefix::ptr::from_raw_parts_mut(ptr as *mut (), len)); + + uninit + }); + + ( + quote! { + #[inline] + pub fn fixed(&self) -> (& #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *const Self).to_raw_parts(); + (&*(ptr as *const #sized_ty_for_impl), len) + } + } + + #[inline] + pub fn fixed_mut(&mut self) -> (&mut #sized_ty_for_impl, usize) { + unsafe { + let (ptr, len) = (self as *mut Self).to_raw_parts(); + (&mut *(ptr as *mut #sized_ty_for_impl), len) + } + } + }, + quote! { + /// Convert a sized prefix to an unsized structure with the given length. + /// + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + pub unsafe fn flex_ref(&self, len: usize) -> &#dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + #flex_ref_inner + } + + /// Convert a mutable sized prefix to an unsized structure with the given length. + /// + /// SAFETY: Underlying storage is initialized up to at least `len` elements. + #[inline] + pub unsafe fn flex_ref_mut(&mut self, len: usize) -> &mut #dst_ty_for_impl { + // SAFETY: Reference is always valid as pointer. Caller is guaranteeing `len`. + #flex_ref_mut_inner + } + + /// Construct DST variant from a pointer and a size. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage is fully initialized up to at least `len` elements. + #[inline] + pub unsafe fn flex_ptr<'unbounded>(ptr: *const Self, len: usize) -> &'unbounded #dst_ty_for_impl { + #flex_ptr_inner + } + + /// Construct mutable DST variant from a pointer and a + /// size. The returned `&mut` reference is initialized + /// pointing to memory referenced by `ptr`, but there's + /// no requirement that that memory be initialized. + /// + /// NOTE: lifetime of returned reference is not tied to any underlying storage. + /// SAFETY: `ptr` is valid. Underlying storage has space for at least `len` elements. + #[inline] + pub unsafe fn flex_ptr_mut<'unbounded>( + ptr: *mut Self, + len: usize, + ) -> ::#prefix::mem::MaybeUninit<&'unbounded mut #dst_ty_for_impl> { + #flex_ptr_mut_inner + } + }, + ) + } else { + (quote!(), quote!()) + }; + + quote! { + impl #impl_generics_labels #dst_ty_for_impl { + #layout + #from_ptr_dst + } + + impl #impl_generics_labels #sized_ty_for_impl { + #from_ptr_sized + } + } + } +} + impl Method { fn codegen_method( &self, @@ -2573,12 +2961,13 @@ method_names: &mut HashSet, result: &mut CodegenResult<'_>, _parent: &CompInfo, + parent_id: DiscoveredItemId, ) { assert!({ let cc = &ctx.options().codegen_config; match self.kind() { MethodKind::Constructor => cc.constructors(), - MethodKind::Destructor => cc.destructors(), + MethodKind::Destructor | MethodKind::VirtualDestructor { .. } => cc.destructors(), MethodKind::Static | MethodKind::Normal | @@ -2598,10 +2987,7 @@ } let function = function_item.expect_function(); let times_seen = function.codegen(ctx, result, function_item); - let times_seen = match times_seen { - Some(seen) => seen, - None => return, - }; + let Some(times_seen) = times_seen else { return }; let signature_item = ctx.resolve_item(function.signature()); let mut name = match self.kind() { MethodKind::Constructor => "new".into(), @@ -2609,9 +2995,10 @@ _ => function.name().to_owned(), }; - let signature = match *signature_item.expect_type().kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("How in the world?"), + let TypeKind::Function(ref signature) = + *signature_item.expect_type().kind() + else { + panic!("How in the world?") }; let supported_abi = signature.abi(ctx, Some(&*name)).is_ok(); @@ -2630,7 +3017,7 @@ let mut new_name; while { - new_name = format!("{}{}", name, count); + new_name = format!("{name}{count}"); method_names.contains(&new_name) } { count += 1; @@ -2641,9 +3028,16 @@ method_names.insert(name.clone()); + utils::call_discovered_item_callback(ctx, function_item, || { + DiscoveredItem::Method { + parent: parent_id, + final_name: name.clone(), + } + }); + let mut function_name = function_item.canonical_name(ctx); if times_seen > 0 { - write!(&mut function_name, "{}", times_seen).unwrap(); + write!(&mut function_name, "{times_seen}").unwrap(); } let function_name = ctx.rust_ident(function_name); let mut args = utils::fnsig_arguments(ctx, signature); @@ -2676,32 +3070,19 @@ // variable called `__bindgen_tmp` we're going to create. if self.is_constructor() { let prefix = ctx.trait_prefix(); - let tmp_variable_decl = if ctx - .options() - .rust_features() - .maybe_uninit - { - exprs[0] = quote! { - __bindgen_tmp.as_mut_ptr() - }; - quote! { - let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit() - } - } else { - exprs[0] = quote! { - &mut __bindgen_tmp - }; - quote! { - let mut __bindgen_tmp = ::#prefix::mem::uninitialized() - } + exprs[0] = quote! { + __bindgen_tmp.as_mut_ptr() }; + let tmp_variable_decl = quote! { + let mut __bindgen_tmp = ::#prefix::mem::MaybeUninit::uninit() + }; stmts.push(tmp_variable_decl); } else if !self.is_static() { assert!(!exprs.is_empty()); exprs[0] = quote! { self }; - }; + } let call = quote! { #function_name (#( #exprs ),* ) @@ -2710,24 +3091,16 @@ stmts.push(call); if self.is_constructor() { - stmts.push(if ctx.options().rust_features().maybe_uninit { - quote! { + stmts.push(quote! { __bindgen_tmp.assume_init() - } - } else { - quote! { - __bindgen_tmp - } - }) + }); } let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*)); let mut attrs = vec![attributes::inline()]; - if signature.must_use() && - ctx.options().rust_features().must_use_function - { + if signature.must_use() { attrs.push(attributes::must_use()); } @@ -2742,11 +3115,11 @@ } /// A helper type that represents different enum variations. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] pub enum EnumVariation { /// The code for this enum will use a Rust enum. Note that creating this in unsafe code /// (including FFI) with an invalid value will invoke undefined behaviour, whether or not - /// its marked as non_exhaustive. + /// its marked as `#[non_exhaustive]`. Rust { /// Indicates whether the generated struct should be `#[non_exhaustive]` non_exhaustive: bool, @@ -2759,29 +3132,24 @@ is_global: bool, }, /// The code for this enum will use consts + #[default] Consts, /// The code for this enum will use a module containing consts ModuleConsts, } impl EnumVariation { - fn is_rust(&self) -> bool { - matches!(*self, EnumVariation::Rust { .. }) + fn is_rust(self) -> bool { + matches!(self, EnumVariation::Rust { .. }) } /// Both the `Const` and `ModuleConsts` variants will cause this to return /// true. - fn is_const(&self) -> bool { - matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts) + fn is_const(self) -> bool { + matches!(self, EnumVariation::Consts | EnumVariation::ModuleConsts) } } -impl Default for EnumVariation { - fn default() -> EnumVariation { - EnumVariation::Consts - } -} - impl fmt::Display for EnumVariation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s = match self { @@ -2811,7 +3179,7 @@ } } -impl std::str::FromStr for EnumVariation { +impl FromStr for EnumVariation { type Err = std::io::Error; /// Create a `EnumVariation` from a string. @@ -2849,313 +3217,355 @@ } } +struct EnumBuilder { + /// Type identifier of the enum. + /// + /// This is the base name, i.e. for `ModuleConst` enums, this does not include the module name. + enum_type: Ident, + /// Attributes applying to the enum type + attrs: Vec, + /// The representation of the enum, e.g. `u32`. + repr: syn::Type, + /// The enum kind we are generating + kind: EnumBuilderKind, + /// A list of all variants this enum has. + enum_variants: Vec, +} + /// A helper type to construct different enum variations. -enum EnumBuilder<'a> { +enum EnumBuilderKind { Rust { - attrs: Vec, - ident: Ident, - tokens: proc_macro2::TokenStream, - emitted_any_variants: bool, + non_exhaustive: bool, }, NewType { - canonical_name: &'a str, - tokens: proc_macro2::TokenStream, is_bitfield: bool, is_global: bool, + /// if the enum is named or not. + is_anonymous: bool, }, Consts { - variants: Vec, + needs_typedef: bool, }, ModuleConsts { - module_name: &'a str, - module_items: Vec, + module_name: Ident, }, } -impl<'a> EnumBuilder<'a> { +impl EnumBuilder { /// Returns true if the builder is for a rustified enum. fn is_rust_enum(&self) -> bool { - matches!(*self, EnumBuilder::Rust { .. }) + matches!(self.kind, EnumBuilderKind::Rust { .. }) } /// Create a new enum given an item builder, a canonical name, a name for /// the representation, and which variation it should be generated as. fn new( - name: &'a str, - mut attrs: Vec, - repr: syn::Type, + name: &str, + attrs: Vec, + repr: &syn::Type, enum_variation: EnumVariation, has_typedef: bool, + enum_is_anonymous: bool, ) -> Self { let ident = Ident::new(name, Span::call_site()); + // For most variants this is the same + let mut enum_ty = ident.clone(); - match enum_variation { + let kind = match enum_variation { EnumVariation::NewType { is_bitfield, is_global, - } => EnumBuilder::NewType { - canonical_name: name, - tokens: quote! { - #( #attrs )* - pub struct #ident (pub #repr); - }, + } => EnumBuilderKind::NewType { is_bitfield, is_global, + is_anonymous: enum_is_anonymous, }, - EnumVariation::Rust { .. } => { - // `repr` is guaranteed to be Rustified in Enum::codegen - attrs.insert(0, quote! { #[repr( #repr )] }); - let tokens = quote!(); - EnumBuilder::Rust { - attrs, - ident, - tokens, - emitted_any_variants: false, - } + EnumVariation::Rust { non_exhaustive } => { + EnumBuilderKind::Rust { non_exhaustive } } - EnumVariation::Consts => { - let mut variants = Vec::new(); + EnumVariation::Consts => EnumBuilderKind::Consts { + needs_typedef: !has_typedef, + }, - if !has_typedef { - variants.push(quote! { - #( #attrs )* - pub type #ident = #repr; - }); - } - - EnumBuilder::Consts { variants } - } - EnumVariation::ModuleConsts => { - let ident = Ident::new( + enum_ty = Ident::new( CONSTIFIED_ENUM_MODULE_REPR_NAME, Span::call_site(), ); - let type_definition = quote! { - #( #attrs )* - pub type #ident = #repr; - }; - EnumBuilder::ModuleConsts { - module_name: name, - module_items: vec![type_definition], + EnumBuilderKind::ModuleConsts { + module_name: ident.clone(), } } + }; + EnumBuilder { + enum_type: enum_ty, + attrs, + repr: repr.clone(), + kind, + enum_variants: vec![], } } /// Add a variant to this enum. fn with_variant( - self, + mut self, ctx: &BindgenContext, variant: &EnumVariant, + variant_doc: proc_macro2::TokenStream, mangling_prefix: Option<&str>, - rust_ty: syn::Type, - result: &mut CodegenResult<'_>, + rust_ty: &syn::Type, is_ty_named: bool, ) -> Self { let variant_name = ctx.rust_mangle(variant.name()); let is_rust_enum = self.is_rust_enum(); let expr = match variant.val() { EnumVariantValue::Boolean(v) if is_rust_enum => { - helpers::ast_ty::uint_expr(v as u64) + helpers::ast_ty::uint_expr(u64::from(v)) } EnumVariantValue::Boolean(v) => quote!(#v), EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), EnumVariantValue::Unsigned(v) => helpers::ast_ty::uint_expr(v), }; - let mut doc = quote! {}; - if ctx.options().generate_comments { - if let Some(raw_comment) = variant.comment() { - let comment = ctx.options().process_comment(raw_comment); - doc = attributes::doc(comment); - } - } - - match self { - EnumBuilder::Rust { - attrs, - ident, - tokens, - emitted_any_variants: _, - } => { + match self.kind { + EnumBuilderKind::Rust { .. } => { let name = ctx.rust_ident(variant_name); - EnumBuilder::Rust { - attrs, - ident, - tokens: quote! { - #tokens - #doc - #name = #expr, - }, - emitted_any_variants: true, - } + self.enum_variants.push(EnumVariantInfo { + variant_name: name, + variant_doc, + value: expr, + }); + self } - EnumBuilder::NewType { - canonical_name, - is_global, - .. - } => { - if ctx.options().rust_features().associated_const && - is_ty_named && - !is_global - { - let enum_ident = ctx.rust_ident(canonical_name); - let variant_ident = ctx.rust_ident(variant_name); - - result.push(quote! { - impl #enum_ident { - #doc - pub const #variant_ident : #rust_ty = #rust_ty ( #expr ); - } - }); + EnumBuilderKind::NewType { is_global, .. } => { + let variant_ident = if is_ty_named && !is_global { + ctx.rust_ident(variant_name) } else { - let ident = ctx.rust_ident(match mangling_prefix { + ctx.rust_ident(match mangling_prefix { Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) + Cow::Owned(format!("{prefix}_{variant_name}")) } None => variant_name, - }); - result.push(quote! { - #doc - pub const #ident : #rust_ty = #rust_ty ( #expr ); - }); - } + }) + }; + self.enum_variants.push(EnumVariantInfo { + variant_name: variant_ident, + variant_doc, + value: quote! { #rust_ty ( #expr )}, + }); self } - EnumBuilder::Consts { .. } => { + EnumBuilderKind::Consts { .. } => { let constant_name = match mangling_prefix { Some(prefix) => { - Cow::Owned(format!("{}_{}", prefix, variant_name)) + Cow::Owned(format!("{prefix}_{variant_name}")) } None => variant_name, }; let ident = ctx.rust_ident(constant_name); - result.push(quote! { - #doc - pub const #ident : #rust_ty = #expr ; + self.enum_variants.push(EnumVariantInfo { + variant_name: ident, + variant_doc, + value: quote! { #expr }, }); self } - EnumBuilder::ModuleConsts { - module_name, - mut module_items, - } => { + EnumBuilderKind::ModuleConsts { .. } => { let name = ctx.rust_ident(variant_name); - let ty = ctx.rust_ident(CONSTIFIED_ENUM_MODULE_REPR_NAME); - module_items.push(quote! { - #doc - pub const #name : #ty = #expr ; + self.enum_variants.push(EnumVariantInfo { + variant_name: name, + variant_doc, + value: quote! { #expr }, }); + self + } + } + } - EnumBuilder::ModuleConsts { - module_name, - module_items, + fn newtype_bitfield_impl( + prefix: &Ident, + rust_ty: &syn::Type, + ) -> proc_macro2::TokenStream { + let rust_ty_name = &rust_ty; + quote! { + impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty { + type Output = Self; + + #[inline] + fn bitor(self, other: Self) -> Self { + #rust_ty_name(self.0 | other.0) } } + impl ::#prefix::ops::BitOrAssign for #rust_ty { + #[inline] + fn bitor_assign(&mut self, rhs: #rust_ty) { + self.0 |= rhs.0; + } + } + impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty { + type Output = Self; + + #[inline] + fn bitand(self, other: Self) -> Self { + #rust_ty_name(self.0 & other.0) + } + } + impl ::#prefix::ops::BitAndAssign for #rust_ty { + #[inline] + fn bitand_assign(&mut self, rhs: #rust_ty) { + self.0 &= rhs.0; + } + } } } fn build( self, ctx: &BindgenContext, - rust_ty: syn::Type, - result: &mut CodegenResult<'_>, + rust_ty: &syn::Type, ) -> proc_macro2::TokenStream { - match self { - EnumBuilder::Rust { - attrs, - ident, - tokens, - emitted_any_variants, - .. - } => { - let variants = if !emitted_any_variants { - quote!(__bindgen_cannot_repr_c_on_empty_enum = 0) - } else { - tokens - }; + let enum_ident = self.enum_type; + // 1. Construct a list of the enum variants + let variants = match self.kind { + EnumBuilderKind::Rust { .. } => { + let mut variants = vec![]; + + for v in self.enum_variants { + let variant_doc = &v.variant_doc; + let variant_ident = &v.variant_name; + let variant_value = &v.value; + + variants.push(quote! { + #variant_doc + #variant_ident = #variant_value, + }); + } + + if variants.is_empty() { + variants.push( + quote! {__bindgen_cannot_repr_c_on_empty_enum = 0,}, + ); + } + variants + } + EnumBuilderKind::NewType { .. } => { + let mut variants = vec![]; + + for v in self.enum_variants { + let variant_doc = &v.variant_doc; + let variant_ident = &v.variant_name; + let variant_value = &v.value; + + variants.push(quote! { + #variant_doc + pub const #variant_ident: #enum_ident = #variant_value; + }); + } + variants + } + EnumBuilderKind::Consts { .. } | + EnumBuilderKind::ModuleConsts { .. } => { + let mut variants = vec![]; + + for v in self.enum_variants { + let variant_doc = &v.variant_doc; + let variant_ident = &v.variant_name; + let variant_value = &v.value; + + variants.push(quote! { + #variant_doc + pub const #variant_ident: #enum_ident = #variant_value; + }); + } + variants + } + }; + let attrs = self.attrs; + let enum_repr = &self.repr; + + // 2. Generate the enum representation + match self.kind { + EnumBuilderKind::Rust { non_exhaustive } => { + let non_exhaustive_opt = + non_exhaustive.then(attributes::non_exhaustive); + quote! { + // Note: repr is on top of attrs to keep the test expectations diff small. + // a future commit could move it further down. + #[repr(#enum_repr)] + #non_exhaustive_opt #( #attrs )* - pub enum #ident { - #variants + pub enum #enum_ident { + #( #variants )* } } } - EnumBuilder::NewType { - canonical_name, - tokens, + EnumBuilderKind::NewType { is_bitfield, - .. + is_global, + is_anonymous, } => { - if !is_bitfield { - return tokens; - } - - let rust_ty_name = ctx.rust_ident_raw(canonical_name); - let prefix = ctx.trait_prefix(); - - result.push(quote! { - impl ::#prefix::ops::BitOr<#rust_ty> for #rust_ty { - type Output = Self; - - #[inline] - fn bitor(self, other: Self) -> Self { - #rust_ty_name(self.0 | other.0) - } + // There doesn't seem to be a technical reason why we generate + // anon enum variants as global constants. + // We keep this behavior to avoid breaking changes in the bindings. + let impl_variants = if is_anonymous || is_global { + quote! { + #( #variants )* } - }); - - result.push(quote! { - impl ::#prefix::ops::BitOrAssign for #rust_ty { - #[inline] - fn bitor_assign(&mut self, rhs: #rust_ty) { - self.0 |= rhs.0; + } else { + quote! { + impl #enum_ident { + #( #variants )* } } - }); + }; - result.push(quote! { - impl ::#prefix::ops::BitAnd<#rust_ty> for #rust_ty { - type Output = Self; + let prefix = ctx.trait_prefix(); + let bitfield_impl_opt = is_bitfield + .then(|| Self::newtype_bitfield_impl(&prefix, rust_ty)); - #[inline] - fn bitand(self, other: Self) -> Self { - #rust_ty_name(self.0 & other.0) - } - } - }); + quote! { + // Previously variant impls where before the enum definition. + // lets keep this as is for now, to reduce the diff in generated bindings. + #impl_variants - result.push(quote! { - impl ::#prefix::ops::BitAndAssign for #rust_ty { - #[inline] - fn bitand_assign(&mut self, rhs: #rust_ty) { - self.0 &= rhs.0; - } + #bitfield_impl_opt + + #[repr(transparent)] + #( #attrs )* + pub struct #enum_ident (pub #enum_repr); + } + } + EnumBuilderKind::Consts { needs_typedef } => { + let typedef_opt = needs_typedef.then(|| { + quote! { + #( #attrs )* + pub type #enum_ident = #enum_repr; } }); + quote! { + #( #variants )* - tokens + #typedef_opt + } } - EnumBuilder::Consts { variants, .. } => quote! { #( #variants )* }, - EnumBuilder::ModuleConsts { - module_items, - module_name, - .. - } => { - let ident = ctx.rust_ident(module_name); + EnumBuilderKind::ModuleConsts { module_name, .. } => { quote! { - pub mod #ident { - #( #module_items )* + // todo: Probably some attributes, e.g. `cfg` should apply to the `mod`. + pub mod #module_name { + #( #attrs )* + pub type #enum_ident = #enum_repr; + + #( #variants )* } } } @@ -3173,7 +3583,7 @@ result: &mut CodegenResult<'_>, item: &Item, ) { - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); let name = item.canonical_name(ctx); @@ -3198,18 +3608,17 @@ // * the representation couldn't be determined from the C source // * it was explicitly requested as a bindgen option - let kind = match repr { - Some(repr) => match *repr.canonical_type(ctx).kind() { + let kind = if let Some(repr) = repr { + match *repr.canonical_type(ctx).kind() { TypeKind::Int(int_kind) => int_kind, _ => panic!("Unexpected type as enum repr"), - }, - None => { - warn!( - "Guessing type of enum! Forward declarations of enums \ - shouldn't be legal!" - ); - IntKind::Int } + } else { + warn!( + "Guessing type of enum! Forward declarations of enums \ + shouldn't be legal!" + ); + IntKind::Int }; let signed = kind.is_signed(); @@ -3229,8 +3638,7 @@ (false, 8) => IntKind::U64, _ => { warn!( - "invalid enum decl: signed: {}, size: {}", - signed, size + "invalid enum decl: signed: {signed}, size: {size}" ); IntKind::I32 } @@ -3244,31 +3652,8 @@ let mut attrs = vec![]; - // TODO(emilio): Delegate this to the builders? - match variation { - EnumVariation::Rust { non_exhaustive } => { - if non_exhaustive && - ctx.options().rust_features().non_exhaustive - { - attrs.push(attributes::non_exhaustive()); - } else if non_exhaustive && - !ctx.options().rust_features().non_exhaustive - { - panic!("The rust target you're using doesn't seem to support non_exhaustive enums"); - } - } - EnumVariation::NewType { .. } => { - if ctx.options().rust_features.repr_transparent { - attrs.push(attributes::repr("transparent")); - } else { - attrs.push(attributes::repr("C")); - } - } - _ => {} - }; - if let Some(comment) = item.comment(ctx) { - attrs.push(attributes::doc(comment)); + attrs.push(attributes::doc(&comment)); } if item.must_use(ctx) { @@ -3288,7 +3673,7 @@ DerivableTraits::EQ, ); let mut derives: Vec<_> = derives.into(); - for derive in item.annotations().derives().iter() { + for derive in item.annotations().derives() { if !derives.contains(&derive.as_str()) { derives.push(derive); } @@ -3305,6 +3690,23 @@ // In most cases this will be a no-op, since custom_derives will be empty. derives.extend(custom_derives.iter().map(|s| s.as_str())); + attrs.extend( + item.annotations() + .attributes() + .iter() + .map(|s| s.parse().unwrap()), + ); + + // The custom attribute callback may return a list of attributes; + // add them to the end of the list. + let custom_attributes = ctx.options().all_callbacks(|cb| { + cb.add_attributes(&AttributeInfo { + name: &name, + kind: DeriveTypeKind::Enum, + }) + }); + attrs.extend(custom_attributes.iter().map(|s| s.parse().unwrap())); + attrs.push(attributes::derives(&derives)); } @@ -3318,17 +3720,17 @@ // value. variant_name: &Ident, referenced_name: &Ident, - enum_rust_ty: syn::Type, + enum_rust_ty: &syn::Type, result: &mut CodegenResult<'_>, ) { let constant_name = if enum_.name().is_some() { if ctx.options().prepend_enum_name { - format!("{}_{}", enum_canonical_name, variant_name) + format!("{enum_canonical_name}_{variant_name}") } else { - format!("{}", variant_name) + format!("{variant_name}") } } else { - format!("{}", variant_name) + format!("{variant_name}") }; let constant_name = ctx.rust_ident(constant_name); @@ -3341,9 +3743,21 @@ let repr = repr.to_rust_ty_or_opaque(ctx, item); let has_typedef = ctx.is_enum_typedef_combo(item.id()); - let mut builder = - EnumBuilder::new(&name, attrs, repr, variation, has_typedef); + utils::call_discovered_item_callback(ctx, item, || { + DiscoveredItem::Enum { + final_name: name.clone(), + } + }); + let mut builder = EnumBuilder::new( + &name, + attrs, + &repr, + variation, + has_typedef, + enum_ty.name().is_none(), + ); + // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, Ident>::default(); let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); @@ -3384,28 +3798,33 @@ continue; } + let mut variant_doc = quote! {}; + if ctx.options().generate_comments { + if let Some(raw_comment) = variant.comment() { + let processed_comment = + ctx.options().process_comment(raw_comment); + variant_doc = attributes::doc(&processed_comment); + } + } + match seen_values.entry(variant.val()) { Entry::Occupied(ref entry) => { if variation.is_rust() { let variant_name = ctx.rust_mangle(variant.name()); - let mangled_name = - if is_toplevel || enum_ty.name().is_some() { - variant_name - } else { - let parent_name = - parent_canonical_name.as_ref().unwrap(); + let mangled_name = if is_toplevel || + enum_ty.name().is_some() + { + variant_name + } else { + let parent_name = + parent_canonical_name.as_ref().unwrap(); - Cow::Owned(format!( - "{}_{}", - parent_name, variant_name - )) - }; + Cow::Owned(format!("{parent_name}_{variant_name}")) + }; let existing_variant_name = entry.get(); // Use associated constants for named enums. - if enum_ty.name().is_some() && - ctx.options().rust_features().associated_const - { + if enum_ty.name().is_some() { let enum_canonical_name = &ident; let variant_name = ctx.rust_ident_raw(&*mangled_name); @@ -3422,7 +3841,7 @@ &ident, &Ident::new(&mangled_name, Span::call_site()), existing_variant_name, - enum_rust_ty.clone(), + &enum_rust_ty, result, ); } @@ -3430,9 +3849,9 @@ builder = builder.with_variant( ctx, variant, + variant_doc, constant_mangling_prefix, - enum_rust_ty.clone(), - result, + &enum_rust_ty, enum_ty.name().is_some(), ); } @@ -3441,9 +3860,9 @@ builder = builder.with_variant( ctx, variant, + variant_doc, constant_mangling_prefix, - enum_rust_ty.clone(), - result, + &enum_rust_ty, enum_ty.name().is_some(), ); @@ -3462,7 +3881,7 @@ parent_canonical_name.as_ref().unwrap(); Ident::new( - &format!("{}_{}", parent_name, variant_name), + &format!("{parent_name}_{variant_name}"), Span::call_site(), ) }; @@ -3473,7 +3892,7 @@ &ident, &mangled_name, &variant_name, - enum_rust_ty.clone(), + &enum_rust_ty, result, ); } @@ -3483,17 +3902,24 @@ } } - let item = builder.build(ctx, enum_rust_ty, result); + let item = builder.build(ctx, &enum_rust_ty); result.push(item); } } +struct EnumVariantInfo { + variant_name: Ident, + variant_doc: proc_macro2::TokenStream, + value: proc_macro2::TokenStream, +} + /// Enum for the default type of macro constants. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] pub enum MacroTypeVariation { /// Use i32 or i64 Signed, /// Use u32 or u64 + #[default] Unsigned, } @@ -3507,13 +3933,7 @@ } } -impl Default for MacroTypeVariation { - fn default() -> MacroTypeVariation { - MacroTypeVariation::Unsigned - } -} - -impl std::str::FromStr for MacroTypeVariation { +impl FromStr for MacroTypeVariation { type Err = std::io::Error; /// Create a `MacroTypeVariation` from a string. @@ -3533,13 +3953,14 @@ } /// Enum for how aliases should be translated. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] pub enum AliasVariation { /// Convert to regular Rust alias + #[default] TypeAlias, /// Create a new type by wrapping the old type in a struct and using #[repr(transparent)] NewType, - /// Same as NewStruct but also impl Deref to be able to use the methods of the wrapped type + /// Same as `NewType` but also impl Deref to be able to use the methods of the wrapped type NewTypeDeref, } @@ -3555,13 +3976,7 @@ } } -impl Default for AliasVariation { - fn default() -> AliasVariation { - AliasVariation::TypeAlias - } -} - -impl std::str::FromStr for AliasVariation { +impl FromStr for AliasVariation { type Err = std::io::Error; /// Create an `AliasVariation` from a string. @@ -3610,7 +4025,7 @@ } } -impl std::str::FromStr for NonCopyUnionStyle { +impl FromStr for NonCopyUnionStyle { type Err = std::io::Error; fn from_str(s: &str) -> Result { @@ -3650,7 +4065,7 @@ extra: &Self::Extra, ) -> error::Result { self.try_get_layout(ctx, extra) - .map(|layout| helpers::blob(ctx, layout)) + .map(|layout| helpers::blob(ctx, layout, true)) } } @@ -3676,7 +4091,7 @@ extra: &Self::Extra, ) -> syn::Type { let layout = self.get_layout(ctx, extra); - helpers::blob(ctx, layout) + helpers::blob(ctx, layout, true) } } @@ -3727,9 +4142,9 @@ ) -> error::Result { self.try_to_rust_ty(ctx, extra).or_else(|_| { if let Ok(layout) = self.try_get_layout(ctx, extra) { - Ok(helpers::blob(ctx, layout)) + Ok(helpers::blob(ctx, layout, true)) } else { - Err(error::Error::NoLayoutForOpaqueBlob) + Err(Error::NoLayoutForOpaqueBlob) } }) } @@ -3744,11 +4159,11 @@ /// ### Fallible vs. Infallible Conversions to Rust Types /// /// When should one use this infallible `ToRustTyOrOpaque` trait versus the -/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait +/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` traits? All fallible trait /// implementations that need to convert another thing into a Rust type or /// opaque blob in a nested manner should also use fallible trait methods and /// propagate failure up the stack. Only infallible functions and methods like -/// CodeGenerator implementations should use the infallible +/// `CodeGenerator` implementations should use the infallible /// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely /// we are to get a usable `Layout` even if we can't generate an equivalent Rust /// type for a C++ construct. @@ -3840,7 +4255,7 @@ ctx: &BindgenContext, _: &Item, ) -> error::Result { - self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + self.layout(ctx).ok_or(Error::NoLayoutForOpaqueBlob) } } @@ -3982,7 +4397,7 @@ Ok(syn::parse_quote! { #name }) } ref u @ TypeKind::UnresolvedTypeRef(..) => { - unreachable!("Should have been resolved after parsing {:?}!", u) + unreachable!("Should have been resolved after parsing {u:?}!") } } } @@ -3998,7 +4413,7 @@ ) -> error::Result { item.expect_type() .layout(ctx) - .ok_or(error::Error::NoLayoutForOpaqueBlob) + .ok_or(Error::NoLayoutForOpaqueBlob) } } @@ -4011,7 +4426,7 @@ item: &Item, ) -> error::Result { if self.is_opaque(ctx, item) { - return Err(error::Error::InstantiationOfOpaqueType); + return Err(Error::InstantiationOfOpaqueType); } let def = self @@ -4033,7 +4448,7 @@ // template specialization, and we've hit an instantiation of // that partial specialization. extra_assert!(def.is_opaque(ctx, &())); - return Err(error::Error::InstantiationOfOpaqueType); + return Err(Error::InstantiationOfOpaqueType); } // TODO: If the definition type is a template class/struct @@ -4085,7 +4500,7 @@ syn::parse_quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret }, ), Err(err) => { - if matches!(err, error::Error::UnsupportedAbi(_)) { + if matches!(err, Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( self.name(), self.is_variadic(), @@ -4114,16 +4529,15 @@ result: &mut CodegenResult<'_>, item: &Item, ) -> Self::Return { - debug!("::codegen: item = {:?}", item); + debug!("::codegen: item = {item:?}"); debug_assert!(item.is_enabled_for_codegen(ctx)); let is_internal = matches!(self.linkage(), Linkage::Internal); let signature_item = ctx.resolve_item(self.signature()); let signature = signature_item.kind().expect_type().canonical_type(ctx); - let signature = match *signature.kind() { - TypeKind::Function(ref sig) => sig, - _ => panic!("Signature kind is not a Function: {:?}", signature), + let TypeKind::Function(ref signature) = *signature.kind() else { + panic!("Signature kind is not a Function: {signature:?}") }; if is_internal { @@ -4141,18 +4555,24 @@ } } - // Pure virtual methods have no actual symbol, so we can't generate - // something meaningful for them. - let is_dynamic_function = match self.kind() { - FunctionKind::Method(ref method_kind) - if method_kind.is_pure_virtual() => - { - return None; + let is_pure_virtual = match self.kind() { + FunctionKind::Method(ref method_kind) => { + method_kind.is_pure_virtual() } + FunctionKind::Function => false, + }; + if is_pure_virtual && !ctx.options().generate_pure_virtual_functions { + // Pure virtual methods have no actual symbol, so we can't generate + // something meaningful for them. Downstream code postprocessors + // might want to find out about them. + return None; + } + + let is_dynamic_function = match self.kind() { FunctionKind::Function => { ctx.options().dynamic_library_name.is_some() } - _ => false, + FunctionKind::Method(_) => false, }; // Similar to static member variables in a class template, we can't @@ -4180,7 +4600,7 @@ let mut attributes = vec![]; - if ctx.options().rust_features().must_use_function { + if true { let must_use = signature.must_use() || { let ret_ty = signature .return_type() @@ -4196,12 +4616,12 @@ } if let Some(comment) = item.comment(ctx) { - attributes.push(attributes::doc(comment)); + attributes.push(attributes::doc(&comment)); } let abi = match signature.abi(ctx, Some(name)) { Err(err) => { - if matches!(err, error::Error::UnsupportedAbi(_)) { + if matches!(err, Error::UnsupportedAbi(_)) { unsupported_abi_diagnostic( name, signature.is_variadic(), @@ -4215,8 +4635,7 @@ } Ok(ClangAbi::Unknown(unknown_abi)) => { panic!( - "Invalid or unknown abi {:?} for function {:?} ({:?})", - unknown_abi, canonical_name, self + "Invalid or unknown abi {unknown_abi:?} for function {canonical_name:?} ({self:?})" ); } Ok(abi) => abi, @@ -4226,24 +4645,27 @@ // suffix. let times_seen = result.overload_number(&canonical_name); if times_seen > 0 { - write!(&mut canonical_name, "{}", times_seen).unwrap(); + write!(&mut canonical_name, "{times_seen}").unwrap(); } + utils::call_discovered_item_callback(ctx, item, || { + DiscoveredItem::Function { + final_name: canonical_name.clone(), + } + }); - let mut has_link_name_attr = false; - if let Some(link_name) = self.link_name() { - attributes.push(attributes::link_name::(link_name)); - has_link_name_attr = true; - } else { - let link_name = mangled_name.unwrap_or(name); - if !is_dynamic_function && - !utils::names_will_be_identical_after_mangling( - &canonical_name, - link_name, - Some(abi), - ) - { + let link_name_attr = self.link_name().or_else(|| { + let mangled_name = mangled_name.unwrap_or(name); + (!utils::names_will_be_identical_after_mangling( + &canonical_name, + mangled_name, + Some(abi), + )) + .then_some(mangled_name) + }); + + if let Some(link_name) = link_name_attr { + if !is_dynamic_function { attributes.push(attributes::link_name::(link_name)); - has_link_name_attr = true; } } @@ -4255,8 +4677,9 @@ quote! { #[link(wasm_import_module = #name)] } }); - let should_wrap = - is_internal && ctx.options().wrap_static_fns && !has_link_name_attr; + let should_wrap = is_internal && + ctx.options().wrap_static_fns && + link_name_attr.is_none(); if should_wrap { let name = canonical_name.clone() + ctx.wrap_static_fns_suffix(); @@ -4298,9 +4721,16 @@ let ret = utils::fnsig_return_ty(ctx, signature); let ident = ctx.rust_ident(ident); + + let safety = ctx + .options() + .rust_features + .unsafe_extern_blocks + .then(|| quote!(unsafe)); + let tokens = quote! { #wasm_link_attribute - extern #abi { + #safety extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; } @@ -4315,19 +4745,22 @@ // If we're doing dynamic binding generation, add to the dynamic items. if is_dynamic_function { + let ident_str = ident.to_string(); + let symbol = link_name_attr.unwrap_or(&ident_str); let args_identifiers = utils::fnsig_argument_identifiers(ctx, signature); let ret_ty = utils::fnsig_return_ty(ctx, signature); - result.dynamic_items().push( - ident, + result.dynamic_items().push_func( + &ident, + symbol, abi, signature.is_variadic(), ctx.options().dynamic_link_require_all, - args, - args_identifiers, - ret, - ret_ty, - attributes, + &args, + &args_identifiers, + &ret, + &ret_ty, + &attributes, ctx, ); } else { @@ -4343,13 +4776,11 @@ variadic: bool, location: Option<&crate::clang::SourceLocation>, ctx: &BindgenContext, - error: &error::Error, + error: &Error, ) { warn!( - "Skipping {}function `{}` because the {}", + "Skipping {}function `{fn_name}` because the {error}", if variadic { "variadic " } else { "" }, - fn_name, - error ); #[cfg(feature = "experimental")] @@ -4359,16 +4790,14 @@ let mut diag = Diagnostic::default(); diag.with_title( format!( - "Skipping {}function `{}` because the {}", + "Skipping {}function `{fn_name}` because the {error}", if variadic { "variadic " } else { "" }, - fn_name, - error ), - Level::Warn, + Level::Warning, ) .add_annotation( "No code will be generated for this function.", - Level::Warn, + Level::Warning, ) .add_annotation( format!( @@ -4392,7 +4821,7 @@ } } - diag.display() + diag.display(); } } @@ -4402,8 +4831,7 @@ _ctx: &BindgenContext, ) { warn!( - "Cannot generate wrapper for the static variadic function `{}`.", - fn_name, + "Cannot generate wrapper for the static variadic function `{fn_name}`." ); #[cfg(feature = "experimental")] @@ -4412,7 +4840,7 @@ let mut diag = Diagnostic::default(); - diag.with_title(format!("Cannot generate wrapper for the static function `{}`.", fn_name), Level::Warn) + diag.with_title(format!("Cannot generate wrapper for the static function `{fn_name}`."), Level::Warning) .add_annotation("The `--wrap-static-fns` feature does not support variadic functions.", Level::Note) .add_annotation("No code will be generated for this function.", Level::Note); @@ -4430,7 +4858,7 @@ } } - diag.display() + diag.display(); } } @@ -4445,7 +4873,7 @@ // 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()); + let name = format!("{rust_class_name}::{prefix}{}", method.rust_name()); if ctx.options().blocklisted_items.matches(name) { return; } @@ -4482,8 +4910,7 @@ ctx.wrap_unsafe_ops(body) }; - let method_name = - ctx.rust_ident(format!("{}{}", prefix, method.rust_name())); + let method_name = ctx.rust_ident(format!("{prefix}{}", method.rust_name())); methods.push(quote! { unsafe fn #method_name #sig where ::Target: objc::Message + Sized { @@ -4584,7 +5011,7 @@ }; result.push(struct_block); let mut protocol_set: HashSet = Default::default(); - for protocol_id in self.conforms_to.iter() { + for protocol_id in &self.conforms_to { protocol_set.insert(*protocol_id); let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) @@ -4606,9 +5033,8 @@ .expect_type() .kind(); - let parent = match parent { - TypeKind::ObjCInterface(ref parent) => parent, - _ => break, + let TypeKind::ObjCInterface(parent) = parent else { + break; }; parent_class = parent.parent_class; @@ -4629,7 +5055,7 @@ } }; result.push(impl_trait); - for protocol_id in parent.conforms_to.iter() { + for protocol_id in &parent.conforms_to { if protocol_set.insert(*protocol_id) { let protocol_name = ctx.rust_ident( ctx.resolve_type(protocol_id.expect_type_id(ctx)) @@ -4656,8 +5082,7 @@ result.push(from_block); let error_msg = format!( - "This {} cannot be downcasted to {}", - parent_struct_name, child_struct_name + "This {parent_struct_name} cannot be downcasted to {child_struct_name}" ); let try_into_block = quote! { impl std::convert::TryFrom<#parent_struct> for #class_name { @@ -4716,7 +5141,7 @@ let codegen_items = context.codegen_items(); for (id, item) in context.items() { if codegen_items.contains(&id) { - println!("ir: {:?} = {:#?}", id, item); + println!("ir: {id:?} = {item:#?}"); } } } @@ -4724,10 +5149,9 @@ if let Some(path) = context.options().emit_ir_graphviz.as_ref() { match dot::write_dot_file(context, path) { Ok(()) => info!( - "Your dot file was generated successfully into: {}", - path + "Your dot file was generated successfully into: {path}" ), - Err(e) => warn!("{}", e), + Err(e) => warn!("{e}"), } } @@ -4737,7 +5161,7 @@ "Your depfile was generated successfully into: {}", spec.depfile_path.display() ), - Err(e) => warn!("{}", e), + Err(e) => warn!("{e}"), } } @@ -4750,7 +5174,7 @@ if let Some(ref lib_name) = context.options().dynamic_library_name { let lib_ident = context.rust_ident(lib_name); let dynamic_items_tokens = - result.dynamic_items().get_tokens(lib_ident, context); + result.dynamic_items().get_tokens(&lib_ident, context); result.push(dynamic_items_tokens); } @@ -4764,8 +5188,10 @@ } pub(crate) mod utils { + use super::helpers::BITFIELD_UNIT; use super::serialize::CSerialize; use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; + use crate::callbacks::DiscoveredItemId; use crate::ir::context::BindgenContext; use crate::ir::context::TypeId; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; @@ -4786,14 +5212,10 @@ 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 path = context.options().wrap_static_fns_path.as_ref().map_or_else( + || std::env::temp_dir().join("bindgen").join("extern"), + PathBuf::from, + ); let dir = path.parent().unwrap(); @@ -4814,7 +5236,7 @@ if !context.options().input_headers.is_empty() { for header in &context.options().input_headers { - writeln!(code, "#include \"{}\"", header)?; + writeln!(code, "#include \"{header}\"")?; } writeln!(code)?; @@ -4822,7 +5244,7 @@ if !context.options().input_header_contents.is_empty() { for (name, contents) in &context.options().input_header_contents { - writeln!(code, "// {}\n{}", name, contents)?; + writeln!(code, "// {name}\n{contents}")?; } writeln!(code)?; @@ -4862,10 +5284,10 @@ } match ty.kind() { TypeKind::Alias(type_id_alias) => { - type_id = *type_id_alias + type_id = *type_id_alias; } TypeKind::ResolvedTypeRef(type_id_typedef) => { - type_id = *type_id_typedef + type_id = *type_id_typedef; } _ => break, } @@ -4900,8 +5322,14 @@ ctx: &BindgenContext, result: &mut Vec, ) { + if ctx.options().blocklisted_items.matches(BITFIELD_UNIT) || + ctx.options().blocklisted_types.matches(BITFIELD_UNIT) + { + return; + } + let bitfield_unit_src = include_str!("./bitfield_unit.rs"); - let bitfield_unit_src = if ctx.options().rust_features().min_const_fn { + let bitfield_unit_src = if true { Cow::Borrowed(bitfield_unit_src) } else { Cow::Owned(bitfield_unit_src.replace("const fn ", "fn ")) @@ -4967,7 +5395,7 @@ // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. - let const_fn = if ctx.options().rust_features().min_const_fn { + let const_fn = if true { quote! { const fn } } else { quote! { fn } @@ -5079,7 +5507,7 @@ // If the target supports `const fn`, declare eligible functions // as `const fn` else just `fn`. - let const_fn = if ctx.options().rust_features().min_const_fn { + let const_fn = if true { quote! { const fn } } else { quote! { fn } @@ -5178,6 +5606,39 @@ result.extend(old_items); } + pub(crate) fn prepend_opaque_array_types( + ctx: &BindgenContext, + result: &mut Vec, + ) { + let mut tys = vec![]; + // If Bindgen could only determine the size and alignment of a type, it is represented like + // this. + for align in ctx.opaque_array_types_needed() { + let ident = if align == 1 { + format_ident!("__BindgenOpaqueArray") + } else { + format_ident!("__BindgenOpaqueArray{}", align) + }; + let repr = if align <= 1 { + quote! { #[repr(C)] } + } else { + let explicit = super::helpers::ast_ty::int_expr(align as i64); + quote! { #[repr(C, align(#explicit))] } + }; + tys.push(quote! { + #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] + #repr + pub struct #ident(pub T); + impl Default for #ident<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } + } + }); + } + result.splice(0..0, tys); + } + pub(crate) fn build_path( item: &Item, ctx: &BindgenContext, @@ -5263,7 +5724,7 @@ pub(crate) fn fnsig_argument_type( ctx: &BindgenContext, - ty: &TypeId, + ty: TypeId, ) -> syn::Type { use super::ToPtr; @@ -5285,7 +5746,8 @@ } else { t.to_rust_ty_or_opaque(ctx, &()) }; - stream.to_ptr(ctx.resolve_type(t).is_const()) + stream + .to_ptr(ctx.resolve_type(t).is_const() || arg_ty.is_const()) } TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); @@ -5305,7 +5767,7 @@ pub(crate) fn fnsig_arguments_iter< 'a, - I: Iterator, crate::ir::context::TypeId)>, + I: Iterator, TypeId)>, >( ctx: &BindgenContext, args_iter: I, @@ -5314,14 +5776,13 @@ let mut unnamed_arguments = 0; let mut args = args_iter .map(|(name, ty)| { - let arg_ty = fnsig_argument_type(ctx, ty); + let arg_ty = fnsig_argument_type(ctx, *ty); - let arg_name = match *name { - Some(ref name) => ctx.rust_mangle(name).into_owned(), - None => { - unnamed_arguments += 1; - format!("arg{}", unnamed_arguments) - } + let arg_name = if let Some(ref name) = *name { + ctx.rust_mangle(name).into_owned() + } else { + unnamed_arguments += 1; + format!("arg{unnamed_arguments}") }; assert!(!arg_name.is_empty()); @@ -5334,7 +5795,7 @@ .collect::>(); if is_variadic { - args.push(quote! { ... }) + args.push(quote! { ... }); } args @@ -5360,12 +5821,11 @@ .argument_types() .iter() .map(|&(ref name, _ty)| { - let arg_name = match *name { - Some(ref name) => ctx.rust_mangle(name).into_owned(), - None => { - unnamed_arguments += 1; - format!("arg{}", unnamed_arguments) - } + let arg_name = if let Some(ref name) = *name { + ctx.rust_mangle(name).into_owned() + } else { + unnamed_arguments += 1; + format!("arg{unnamed_arguments}") }; assert!(!arg_name.is_empty()); @@ -5415,7 +5875,7 @@ let mangled_name = mangled_name.as_bytes(); let (mangling_prefix, expect_suffix) = match call_conv { - Some(ClangAbi::Known(Abi::C)) | + Some(ClangAbi::Known(Abi::C | Abi::CUnwind)) | // None is the case for global variables None => { (b'_', false) @@ -5442,7 +5902,7 @@ // Check that the mangled name contains the canonical name after the // prefix - if &mangled_name[1..canonical_name.len() + 1] != canonical_name { + if &mangled_name[1..=canonical_name.len()] != canonical_name { return false; } @@ -5469,5 +5929,29 @@ } true + } + + pub(super) fn call_discovered_item_callback( + ctx: &BindgenContext, + item: &Item, + discovered_item_creator: impl Fn() -> crate::callbacks::DiscoveredItem, + ) { + let source_location = item.location().map(|clang_location| { + let (file, line, col, byte_offset) = clang_location.location(); + let file_name = file.name(); + crate::callbacks::SourceLocation { + line, + col, + byte_offset, + file_name, + } + }); + ctx.options().for_each_callback(|cb| { + cb.new_item_found( + DiscoveredItemId::new(item.id().as_usize()), + discovered_item_creator(), + source_location.as_ref(), + ); + }); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs firefox-140.10.2/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/postprocessing/merge_extern_blocks.rs Mon May 11 04:49:32 2026 @@ -4,7 +4,7 @@ }; pub(super) fn merge_extern_blocks(file: &mut File) { - Visitor.visit_file_mut(file) + Visitor.visit_file_mut(file); } struct Visitor; @@ -12,14 +12,14 @@ impl VisitMut for Visitor { fn visit_file_mut(&mut self, file: &mut File) { visit_items(&mut file.items); - visit_file_mut(self, file) + visit_file_mut(self, file); } fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { visit_items(items); } - visit_item_mod_mut(self, item_mod) + visit_item_mod_mut(self, item_mod); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs firefox-140.10.2/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/postprocessing/sort_semantically.rs Mon May 11 04:49:32 2026 @@ -4,7 +4,7 @@ }; pub(super) fn sort_semantically(file: &mut File) { - Visitor.visit_file_mut(file) + Visitor.visit_file_mut(file); } struct Visitor; @@ -12,14 +12,14 @@ impl VisitMut for Visitor { fn visit_file_mut(&mut self, file: &mut File) { visit_items(&mut file.items); - visit_file_mut(self, file) + visit_file_mut(self, file); } fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) { if let Some((_, ref mut items)) = item_mod.content { visit_items(items); } - visit_item_mod_mut(self, item_mod) + visit_item_mod_mut(self, item_mod); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/serialize.rs firefox-140.10.2/third_party/rust/bindgen/codegen/serialize.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/serialize.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/serialize.rs Mon May 11 04:49:32 2026 @@ -14,8 +14,7 @@ fn get_loc(item: &Item) -> String { item.location() - .map(|x| x.to_string()) - .unwrap_or_else(|| "unknown".to_owned()) + .map_or_else(|| "unknown".to_owned(), |x| x.to_string()) } pub(super) trait CSerialize<'a> { @@ -45,7 +44,7 @@ func.serialize(ctx, (self, extra), stack, writer) } kind => Err(CodegenError::Serialize { - msg: format!("Cannot serialize item kind {:?}", kind), + msg: format!("Cannot serialize item kind {kind:?}"), loc: get_loc(self), }), } @@ -72,16 +71,17 @@ }); } - let signature = match ctx.resolve_type(self.signature()).kind() { - TypeKind::Function(signature) => signature, - _ => unreachable!(), + let TypeKind::Function(signature) = + ctx.resolve_type(self.signature()).kind() + else { + unreachable!() }; assert!(!signature.is_variadic()); let name = self.name(); - // Function argoments stored as `(name, type_id)` tuples. + // Function arguments stored as `(name, type_id)` tuples. let args = { let mut count = 0; @@ -102,7 +102,7 @@ } else { Some(( opt_name.unwrap_or_else(|| { - let name = format!("arg_{}", count); + let name = format!("arg_{count}"); count += 1; name }), @@ -114,7 +114,7 @@ }; // The name used for the wrapper self. - let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix()); + let wrap_name = format!("{name}{}", ctx.wrap_static_fns_suffix()); // The function's return type let (ret_item, ret_ty) = { @@ -131,15 +131,15 @@ const INDENT: &str = " "; // Write `wrap_name(args`. - write!(writer, " {}(", wrap_name)?; + write!(writer, " {wrap_name}(")?; serialize_args(&args, ctx, writer)?; if wrap_as_variadic.is_none() { // Write `) { name(` if the function returns void and `) { return name(` if it does not. if ret_ty.is_void() { - write!(writer, ") {{ {}(", name)?; + write!(writer, ") {{ {name}(")?; } else { - write!(writer, ") {{ return {}(", name)?; + write!(writer, ") {{ return {name}(")?; } } else { // Write `, ...) {` @@ -165,7 +165,7 @@ if !ret_ty.is_void() { write!(writer, "ret = ")?; } - write!(writer, "{}(", name)?; + write!(writer, "{name}(")?; } // Get the arguments names and insert at the right place if necessary `ap` @@ -179,7 +179,7 @@ // Write `arg_names);`. serialize_sep(", ", args.iter(), ctx, writer, |name, _, buf| { - write!(buf, "{}", name).map_err(From::from) + write!(buf, "{name}").map_err(From::from) })?; #[rustfmt::skip] write!(writer, ");{}", if wrap_as_variadic.is_none() { " " } else { "\n" })?; @@ -198,7 +198,7 @@ } } -impl<'a> CSerialize<'a> for TypeId { +impl CSerialize<'_> for TypeId { type Extra = (); fn serialize( @@ -228,13 +228,13 @@ if self.is_const() { write!(writer, "const ")?; } - write!(writer, "void")? + write!(writer, "void")?; } TypeKind::NullPtr => { if self.is_const() { write!(writer, "const ")?; } - write!(writer, "nullptr_t")? + write!(writer, "nullptr_t")?; } TypeKind::Int(int_kind) => { if self.is_const() { @@ -257,8 +257,7 @@ int_kind => { return Err(CodegenError::Serialize { msg: format!( - "Cannot serialize integer kind {:?}", - int_kind + "Cannot serialize integer kind {int_kind:?}" ), loc: get_loc(item), }) @@ -286,7 +285,7 @@ FloatKind::Float => write!(writer, "float complex")?, FloatKind::Double => write!(writer, "double complex")?, FloatKind::LongDouble => { - write!(writer, "long double complex")? + write!(writer, "long double complex")?; } FloatKind::Float128 => write!(writer, "__complex128")?, } @@ -294,9 +293,9 @@ TypeKind::Alias(type_id) => { if let Some(name) = self.name() { if self.is_const() { - write!(writer, "const {}", name)?; + write!(writer, "const {name}")?; } else { - write!(writer, "{}", name)?; + write!(writer, "{name}")?; } } else { type_id.serialize(ctx, (), stack, writer)?; @@ -304,7 +303,7 @@ } TypeKind::Array(type_id, length) => { type_id.serialize(ctx, (), stack, writer)?; - write!(writer, " [{}]", length)? + write!(writer, " [{length}]")?; } TypeKind::Function(signature) => { if self.is_const() { @@ -320,7 +319,7 @@ write!(writer, " (")?; while let Some(item) = stack.pop() { - write!(writer, "{}", item)?; + write!(writer, "{item}")?; } write!(writer, ")")?; @@ -342,14 +341,14 @@ type_id.serialize(ctx, (), &mut stack, buf) }, )?; - write!(writer, ")")? + write!(writer, ")")?; } } TypeKind::ResolvedTypeRef(type_id) => { if self.is_const() { write!(writer, "const ")?; } - type_id.serialize(ctx, (), stack, writer)? + type_id.serialize(ctx, (), stack, writer)?; } TypeKind::Pointer(type_id) => { if self.is_const() { @@ -357,7 +356,7 @@ } else { stack.push("*".to_owned()); } - type_id.serialize(ctx, (), stack, writer)? + type_id.serialize(ctx, (), stack, writer)?; } TypeKind::Comp(comp_info) => { if self.is_const() { @@ -367,9 +366,9 @@ let name = item.canonical_name(ctx); match comp_info.kind() { - CompKind::Struct => write!(writer, "struct {}", name)?, - CompKind::Union => write!(writer, "union {}", name)?, - }; + CompKind::Struct => write!(writer, "struct {name}")?, + CompKind::Union => write!(writer, "union {name}")?, + } } TypeKind::Enum(_enum_ty) => { if self.is_const() { @@ -377,20 +376,20 @@ } let name = item.canonical_name(ctx); - write!(writer, "enum {}", name)?; + write!(writer, "enum {name}")?; } ty => { return Err(CodegenError::Serialize { - msg: format!("Cannot serialize type kind {:?}", ty), + 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)?; + write!(writer, "{item}")?; } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/codegen/struct_layout.rs firefox-140.10.2/third_party/rust/bindgen/codegen/struct_layout.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/codegen/struct_layout.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/codegen/struct_layout.rs Mon May 11 04:49:32 2026 @@ -7,7 +7,7 @@ use crate::ir::layout::Layout; use crate::ir::ty::{Type, TypeKind}; use crate::FieldVisibilityKind; -use proc_macro2::{self, Ident, Span}; +use proc_macro2::{Ident, Span}; use std::cmp; const MAX_GUARANTEED_ALIGN: usize = 8; @@ -28,6 +28,7 @@ max_field_align: usize, last_field_was_bitfield: bool, visibility: FieldVisibilityKind, + last_field_was_flexible_array: bool, } /// Returns a size aligned to a given value. @@ -44,23 +45,6 @@ size + align - rem } -/// Returns the lower power of two byte count that can hold at most n bits. -pub(crate) fn bytes_from_bits_pow2(mut n: usize) -> usize { - if n == 0 { - return 0; - } - - if n <= 8 { - return 1; - } - - if !n.is_power_of_two() { - n = n.next_power_of_two(); - } - - n / 8 -} - #[test] fn test_align_to() { assert_eq!(align_to(1, 1), 1); @@ -70,20 +54,6 @@ assert_eq!(align_to(17, 4), 20); } -#[test] -fn test_bytes_from_bits_pow2() { - assert_eq!(bytes_from_bits_pow2(0), 0); - for i in 1..9 { - assert_eq!(bytes_from_bits_pow2(i), 1); - } - for i in 9..17 { - assert_eq!(bytes_from_bits_pow2(i), 2); - } - for i in 17..33 { - assert_eq!(bytes_from_bits_pow2(i), 4); - } -} - impl<'a> StructLayoutTracker<'a> { pub(crate) fn new( ctx: &'a BindgenContext, @@ -110,6 +80,7 @@ latest_field_layout: None, max_field_align: 0, last_field_was_bitfield: false, + last_field_was_flexible_array: false, } } @@ -121,6 +92,10 @@ self.is_rust_union } + pub(crate) fn saw_flexible_array(&mut self) { + self.last_field_was_flexible_array = true; + } + pub(crate) fn saw_vtable(&mut self) { debug!("saw vtable for {}", self.name); @@ -142,7 +117,7 @@ } pub(crate) fn saw_bitfield_unit(&mut self, layout: Layout) { - debug!("saw bitfield unit for {}: {:?}", self.name, layout); + debug!("saw bitfield unit for {}: {layout:?}", self.name); self.align_to_latest_field(layout); @@ -242,12 +217,9 @@ ); debug!( - "align field {} to {}/{} with {} padding bytes {:?}", - field_name, + "align field {field_name} to {}/{} with {padding_bytes} padding bytes {field_layout:?}", self.latest_offset, field_offset.unwrap_or(0) / 8, - padding_bytes, - field_layout ); let padding_align = if force_padding { @@ -263,15 +235,19 @@ } }; - self.latest_offset += field_layout.size; + if is_union { + self.latest_offset = + cmp::max(self.latest_offset, field_layout.size); + } else { + self.latest_offset += field_layout.size; + } self.latest_field_layout = Some(field_layout); self.max_field_align = cmp::max(self.max_field_align, field_layout.align); self.last_field_was_bitfield = false; debug!( - "Offset: {}: {} -> {}", - field_name, + "Offset: {field_name}: {} -> {}", self.latest_offset - field_layout.size, self.latest_offset ); @@ -295,14 +271,18 @@ return None; } + // Also doesn't make sense for structs with flexible array members + if self.last_field_was_flexible_array { + return None; + } + if self.latest_offset == comp_layout.size { // This struct does not contain tail padding. return None; } trace!( - "need a tail padding field for {}: offset {} -> size {}", - comp_name, + "need a tail padding field for {comp_name}: offset {} -> size {}", self.latest_offset, comp_layout.size ); @@ -314,10 +294,7 @@ &mut self, layout: Layout, ) -> Option { - debug!( - "pad_struct:\n\tself = {:#?}\n\tlayout = {:#?}", - self, layout - ); + debug!("pad_struct:\n\tself = {self:#?}\n\tlayout = {layout:#?}"); if layout.size < self.latest_offset { warn!( @@ -333,7 +310,7 @@ return None; } - let repr_align = self.ctx.options().rust_features().repr_align; + let repr_align = true; // We always pad to get to the correct size if the struct is one of // those we can't align properly. @@ -357,7 +334,7 @@ Layout::new(padding_bytes, layout.align) }; - debug!("pad bytes to struct {}, {:?}", self.name, layout); + debug!("pad bytes to struct {}, {layout:?}", self.name); Some(self.padding_field(layout)) } else { @@ -366,7 +343,7 @@ } pub(crate) fn requires_explicit_align(&self, layout: Layout) -> bool { - let repr_align = self.ctx.options().rust_features().repr_align; + let repr_align = true; // Always force explicit repr(align) for stuff more than 16-byte aligned // to work-around https://github.com/rust-lang/rust/issues/54341. @@ -390,13 +367,13 @@ } fn padding_field(&mut self, layout: Layout) -> proc_macro2::TokenStream { - let ty = helpers::blob(self.ctx, layout); + let ty = helpers::blob(self.ctx, layout, false); let padding_count = self.padding_count; self.padding_count += 1; let padding_field_name = Ident::new( - &format!("__bindgen_padding_{}", padding_count), + &format!("__bindgen_padding_{padding_count}"), Span::call_site(), ); @@ -411,23 +388,22 @@ /// Returns whether the new field is known to merge with a bitfield. /// - /// This is just to avoid doing the same check also in pad_field. + /// This is just to avoid doing the same check also in `pad_field`. fn align_to_latest_field(&mut self, new_field_layout: Layout) -> bool { if self.is_packed { // Skip to align fields when packed. return false; } - let layout = match self.latest_field_layout { - Some(l) => l, - None => return false, + let Some(layout) = self.latest_field_layout else { + return false; }; // If it was, we may or may not need to align, depending on what the // current field alignment and the bitfield size and alignment are. debug!( - "align_to_bitfield? {}: {:?} {:?}", - self.last_field_was_bitfield, layout, new_field_layout + "align_to_bitfield? {}: {layout:?} {new_field_layout:?}", + self.last_field_was_bitfield, ); // Avoid divide-by-zero errors if align is 0. diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/deps.rs firefox-140.10.2/third_party/rust/bindgen/deps.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/deps.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/deps.rs Mon May 11 04:49:32 2026 @@ -18,7 +18,7 @@ let mut buf = format!("{}:", escape(&self.output_module)); for file in deps { - buf = format!("{} {}", buf, escape(file)); + buf = format!("{buf} {}", escape(file)); } buf } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/diagnostics.rs firefox-140.10.2/third_party/rust/bindgen/diagnostics.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/diagnostics.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/diagnostics.rs Mon May 11 04:49:32 2026 @@ -6,34 +6,10 @@ use std::io::{self, BufRead, BufReader}; use std::{borrow::Cow, fs::File}; -use annotate_snippets::{ - display_list::{DisplayList, FormatOptions}, - snippet::{Annotation, Slice as ExtSlice, Snippet}, -}; +use annotate_snippets::{Renderer, Snippet}; -use annotate_snippets::snippet::AnnotationType; +pub(crate) use annotate_snippets::Level; -#[derive(Clone, Copy, Debug)] -pub(crate) enum Level { - Error, - Warn, - Info, - Note, - Help, -} - -impl From for AnnotationType { - fn from(level: Level) -> Self { - match level { - Level::Error => Self::Error, - Level::Warn => Self::Warning, - Level::Info => Self::Info, - Level::Note => Self::Note, - Level::Help => Self::Help, - } - } -} - /// A `bindgen` diagnostic. #[derive(Default)] pub(crate) struct Diagnostic<'a> { @@ -78,55 +54,37 @@ static INVOKED_BY_BUILD_SCRIPT: bool = std::env::var_os("CARGO_CFG_TARGET_ARCH").is_some(); } - let mut title = None; let mut footer = vec![]; let mut slices = vec![]; - if let Some((msg, level)) = &self.title { - title = Some(Annotation { - id: Some("bindgen"), - label: Some(msg.as_ref()), - annotation_type: (*level).into(), - }) - } + let snippet = if let Some((msg, level)) = &self.title { + (*level).title(msg) + } else { + return; + }; for (msg, level) in &self.footer { - footer.push(Annotation { - id: None, - label: Some(msg.as_ref()), - annotation_type: (*level).into(), - }); + footer.push((*level).title(msg)); } // add additional info that this is generated by bindgen // so as to not confuse with rustc warnings - footer.push(Annotation { - id: None, - label: Some("This diagnostic was generated by bindgen."), - annotation_type: AnnotationType::Info, - }); + footer.push( + Level::Info.title("This diagnostic was generated by bindgen."), + ); for slice in &self.slices { if let Some(source) = &slice.source { - slices.push(ExtSlice { - source: source.as_ref(), - line_start: slice.line.unwrap_or_default(), - origin: slice.filename.as_deref(), - annotations: vec![], - fold: false, - }) + let mut snippet = Snippet::source(source) + .line_start(slice.line.unwrap_or_default()); + if let Some(origin) = &slice.filename { + snippet = snippet.origin(origin); + } + slices.push(snippet); } } - let snippet = Snippet { - title, - footer, - slices, - opt: FormatOptions { - color: true, - ..Default::default() - }, - }; - let dl = DisplayList::from(snippet); + let renderer = Renderer::styled(); + let dl = renderer.render(snippet.snippets(slices).footers(footer)); if INVOKED_BY_BUILD_SCRIPT.with(Clone::clone) { // This is just a hack which hides the `warning:` added by cargo at the beginning of @@ -135,10 +93,10 @@ let hide_warning = "\r \r"; let string = dl.to_string(); for line in string.lines() { - println!("cargo:warning={}{}", hide_warning, line); + println!("cargo:warning={hide_warning}{line}"); } } else { - eprintln!("{}\n", dl); + eprintln!("{dl}\n"); } } } @@ -168,8 +126,7 @@ line: usize, col: usize, ) -> &mut Self { - write!(name, ":{}:{}", line, col) - .expect("Writing to a string cannot fail"); + write!(name, ":{line}:{col}").expect("Writing to a string cannot fail"); self.filename = Some(name); self.line = Some(line); self diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/extra_assertions.rs firefox-140.10.2/third_party/rust/bindgen/extra_assertions.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/extra_assertions.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/extra_assertions.rs Mon May 11 04:49:32 2026 @@ -2,7 +2,7 @@ //! and/or CI when the `__testing_only_extra_assertions` feature is enabled. /// Simple macro that forwards to assert! when using -/// __testing_only_extra_assertions. +/// `__testing_only_extra_assertions`. macro_rules! extra_assert { ( $cond:expr ) => { if cfg!(feature = "__testing_only_extra_assertions") { diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/features.rs firefox-140.10.2/third_party/rust/bindgen/features.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/features.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/features.rs Mon May 11 04:49:32 2026 @@ -4,86 +4,303 @@ #![deny(clippy::missing_docs_in_private_items)] #![allow(deprecated)] -use std::cmp::Ordering; -use std::io; use std::str::FromStr; +use std::{fmt, io}; +/// Represents the version of the Rust language to target. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[repr(transparent)] +pub struct RustTarget(Version); + +impl RustTarget { + /// Create a new [`RustTarget`] for a stable release of Rust. + pub fn stable(minor: u64, patch: u64) -> Result { + let target = Self(Version::Stable(minor, patch)); + + if target < EARLIEST_STABLE_RUST { + return Err(InvalidRustTarget::TooEarly); + } + + Ok(target) + } + + const fn minor(&self) -> Option { + match self.0 { + Version::Nightly => None, + Version::Stable(minor, _) => Some(minor), + } + } + + const fn is_compatible(&self, other: &Self) -> bool { + match (self.0, other.0) { + (Version::Stable(minor, _), Version::Stable(other_minor, _)) => { + // We ignore the patch version number as they only include backwards compatible bug + // fixes. + minor >= other_minor + } + // Nightly is compatible with everything + (Version::Nightly, _) => true, + // No stable release is compatible with nightly + (Version::Stable { .. }, Version::Nightly) => false, + } + } +} + +impl Default for RustTarget { + fn default() -> Self { + // Bindgen from build script: default to generating bindings compatible + // with the Rust version currently performing this build. + #[cfg(not(feature = "__cli"))] + { + use std::env; + use std::iter; + use std::process::Command; + use std::sync::OnceLock; + + static CURRENT_RUST: OnceLock> = OnceLock::new(); + + if let Some(current_rust) = *CURRENT_RUST.get_or_init(|| { + let is_build_script = + env::var_os("CARGO_CFG_TARGET_ARCH").is_some(); + if !is_build_script { + return None; + } + + let rustc = env::var_os("RUSTC")?; + let rustc_wrapper = env::var_os("RUSTC_WRAPPER") + .filter(|wrapper| !wrapper.is_empty()); + let wrapped_rustc = + rustc_wrapper.iter().chain(iter::once(&rustc)); + + let mut is_clippy_driver = false; + loop { + let mut wrapped_rustc = wrapped_rustc.clone(); + let mut command = + Command::new(wrapped_rustc.next().unwrap()); + command.args(wrapped_rustc); + if is_clippy_driver { + command.arg("--rustc"); + } + command.arg("--version"); + + let output = command.output().ok()?; + let string = String::from_utf8(output.stdout).ok()?; + + // Version string like "rustc 1.100.0-beta.5 (f0e1d2c3b 2026-10-17)" + let last_line = string.lines().last().unwrap_or(&string); + let (program, rest) = last_line.trim().split_once(' ')?; + if program != "rustc" { + if program.starts_with("clippy") && !is_clippy_driver { + is_clippy_driver = true; + continue; + } + return None; + } + + let number = rest.split([' ', '-', '+']).next()?; + break RustTarget::from_str(number).ok(); + } + }) { + return current_rust; + } + } + + // Bindgen from CLI, or cannot determine compiler version: default to + // generating bindings compatible with the latest stable release of Rust + // that Bindgen knows about. + LATEST_STABLE_RUST + } +} + +impl fmt::Display for RustTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 { + Version::Stable(minor, patch) => write!(f, "1.{minor}.{patch}"), + Version::Nightly => "nightly".fmt(f), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum Version { + Stable(u64, u64), + Nightly, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum InvalidRustTarget { + TooEarly, +} + +impl fmt::Display for InvalidRustTarget { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::TooEarly => write!(f, "the earliest Rust version supported by bindgen is {EARLIEST_STABLE_RUST}"), + } + } +} + +/// This macro defines the Rust editions supported by bindgen. +macro_rules! define_rust_editions { + ($($variant:ident($value:literal) => $minor:literal,)*) => { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] + #[doc = "Represents Rust Edition for the generated bindings"] + pub enum RustEdition { + $( + #[doc = concat!("The ", stringify!($value), " edition of Rust.")] + $variant, + )* + } + + impl FromStr for RustEdition { + type Err = InvalidRustEdition; + + fn from_str(s: &str) -> Result { + match s { + $(stringify!($value) => Ok(Self::$variant),)* + _ => Err(InvalidRustEdition(s.to_owned())), + } + } + } + + impl fmt::Display for RustEdition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + $(Self::$variant => stringify!($value).fmt(f),)* + } + } + } + + impl RustEdition { + pub(crate) const ALL: [Self; [$($value,)*].len()] = [$(Self::$variant,)*]; + + pub(crate) fn is_available(self, target: RustTarget) -> bool { + let Some(minor) = target.minor() else { + return true; + }; + + match self { + $(Self::$variant => $minor <= minor,)* + } + } + } + } +} + +#[derive(Debug)] +pub struct InvalidRustEdition(String); + +impl fmt::Display for InvalidRustEdition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\"{}\" is not a valid Rust edition", self.0) + } +} + +impl std::error::Error for InvalidRustEdition {} + +define_rust_editions! { + Edition2018(2018) => 31, + Edition2021(2021) => 56, + Edition2024(2024) => 85, +} + +impl RustTarget { + /// Returns the latest edition supported by this target. + pub(crate) fn latest_edition(self) -> RustEdition { + RustEdition::ALL + .iter() + .rev() + .find(|edition| edition.is_available(self)) + .copied() + .expect("bindgen should always support at least one edition") + } +} + +impl Default for RustEdition { + fn default() -> Self { + RustTarget::default().latest_edition() + } +} + /// This macro defines the [`RustTarget`] and [`RustFeatures`] types. macro_rules! define_rust_targets { ( - Nightly => {$($nightly_feature:ident $(: #$issue:literal)?),* $(,)?} $(,)? + Nightly => {$($nightly_feature:ident $(($nightly_edition:literal))|* $(: #$issue:literal)?),* $(,)?} $(,)? $( - $(#[$attrs:meta])* - $variant:ident($minor:literal) => {$($feature:ident $(: #$pull:literal)?),* $(,)?}, + $variant:ident($minor:literal) => {$($feature:ident $(($edition:literal))|* $(: #$pull:literal)?),* $(,)?}, )* $(,)? ) => { - /// Represents the version of the Rust language to target. - /// - /// To support a beta release, use the corresponding stable release. - /// - /// This enum will have more variants added as necessary. - #[allow(non_camel_case_types)] - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] - pub enum RustTarget { - /// Rust Nightly + + impl RustTarget { + /// The nightly version of Rust, which introduces the following features:" $(#[doc = concat!( "- [`", stringify!($nightly_feature), "`]", "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")", )])* - Nightly, + #[deprecated = "The use of this constant is deprecated, please use `RustTarget::nightly` instead."] + pub const Nightly: Self = Self::nightly(); + + /// The nightly version of Rust, which introduces the following features:" + $(#[doc = concat!( + "- [`", stringify!($nightly_feature), "`]", + "(", $("https://github.com/rust-lang/rust/pull/", stringify!($issue),)* ")", + )])* + pub const fn nightly() -> Self { + Self(Version::Nightly) + } + $( - #[doc = concat!("Rust 1.", stringify!($minor))] + #[doc = concat!("Version 1.", stringify!($minor), " of Rust, which introduced the following features:")] $(#[doc = concat!( "- [`", stringify!($feature), "`]", "(", $("https://github.com/rust-lang/rust/pull/", stringify!($pull),)* ")", )])* - $(#[$attrs])* - $variant, + #[deprecated = "The use of this constant is deprecated, please use `RustTarget::stable` instead."] + pub const $variant: Self = Self(Version::Stable($minor, 0)); )* - } - impl RustTarget { - fn minor(self) -> Option { - match self { - $( Self::$variant => Some($minor),)* - Self::Nightly => None - } - } - const fn stable_releases() -> [(Self, u64); [$($minor,)*].len()] { [$((Self::$variant, $minor),)*] } } - #[cfg(feature = "__cli")] - /// Strings of allowed `RustTarget` values - pub const RUST_TARGET_STRINGS: &[&str] = &[$(concat!("1.", stringify!($minor)),)*]; - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub(crate) struct RustFeatures { $($(pub(crate) $feature: bool,)*)* $(pub(crate) $nightly_feature: bool,)* } - impl From for RustFeatures { - fn from(target: RustTarget) -> Self { - if target == RustTarget::Nightly { - return Self { - $($($feature: true,)*)* - $($nightly_feature: true,)* - }; - } - + impl RustFeatures { + /// Compute the features that must be enabled in a specific Rust target with a specific edition. + pub(crate) fn new(target: RustTarget, edition: RustEdition) -> Self { let mut features = Self { $($($feature: false,)*)* $($nightly_feature: false,)* }; - $(if target >= RustTarget::$variant { - $(features.$feature = true;)* - })* + if target.is_compatible(&RustTarget::nightly()) { + $( + let editions: &[RustEdition] = &[$(stringify!($nightly_edition).parse::().ok().expect("invalid edition"),)*]; + if editions.is_empty() || editions.contains(&edition) { + features.$nightly_feature = true; + } + )* + } + + $( + if target.is_compatible(&RustTarget::$variant) { + $( + let editions: &[RustEdition] = &[$(stringify!($edition).parse::().ok().expect("invalid edition"),)*]; + + if editions.is_empty() || editions.contains(&edition) { + features.$feature = true; + } + )* + } + )* + features } } @@ -95,43 +312,26 @@ // not stable. define_rust_targets! { Nightly => { - vectorcall_abi, + vectorcall_abi: #124485, + ptr_metadata: #81513, + layout_for_ptr: #69835, }, + Stable_1_82(82) => { + unsafe_extern_blocks: #127921, + }, + Stable_1_77(77) => { + offset_of: #106655, + literal_cstr(2021)|(2024): #117472, + }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 }, Stable_1_64(64) => { core_ffi_c: #94503 }, Stable_1_59(59) => { const_cstr: #54745 }, - Stable_1_47(47) => { larger_arrays: #74060 }, - Stable_1_40(40) => { non_exhaustive: #44109 }, - Stable_1_36(36) => { maybe_uninit: #60445 }, - Stable_1_33(33) => { repr_packed_n: #57049 }, - #[deprecated] - Stable_1_30(30) => { - core_ffi_c_void: #53910, - min_const_fn: #54835, - }, - #[deprecated] - Stable_1_28(28) => { repr_transparent: #51562 }, - #[deprecated] - Stable_1_27(27) => { must_use_function: #48925 }, - #[deprecated] - Stable_1_26(26) => { i128_and_u128: #49101 }, - #[deprecated] - Stable_1_25(25) => { repr_align: #47006 }, - #[deprecated] - Stable_1_21(21) => { builtin_clone_impls: #43690 }, - #[deprecated] - Stable_1_20(20) => { associated_const: #42809 }, - #[deprecated] - Stable_1_19(19) => { untagged_union: #42068 }, - #[deprecated] - Stable_1_17(17) => { static_lifetime_elision: #39265 }, - #[deprecated] - Stable_1_0(0) => {}, + Stable_1_51(51) => {}, } -/// Latest stable release of Rust +/// Latest stable release of Rust that is supported by bindgen pub const LATEST_STABLE_RUST: RustTarget = { // FIXME: replace all this code by // ``` @@ -139,7 +339,7 @@ // .into_iter() // .max_by_key(|(_, m)| m) // .map(|(t, _)| t) - // .unwrap_or(RustTarget::Nightly) + // .unwrap() // ``` // once those operations can be used in constants. let targets = RustTarget::stable_releases(); @@ -165,132 +365,198 @@ } }; -impl Default for RustTarget { - fn default() -> Self { - LATEST_STABLE_RUST - } -} +/// Earliest stable release of Rust that is supported by bindgen +pub const EARLIEST_STABLE_RUST: RustTarget = { + // FIXME: replace all this code by + // ``` + // RustTarget::stable_releases() + // .into_iter() + // .min_by_key(|(_, m)| m) + // .map(|(t, _)| t) + // .unwrap_or(LATEST_STABLE_RUST) + // ``` + // once those operations can be used in constants. + let targets = RustTarget::stable_releases(); -impl PartialOrd for RustTarget { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} + let mut i = 0; + let mut earliest_target = None; + let Some(mut earliest_minor) = LATEST_STABLE_RUST.minor() else { + unreachable!() + }; -impl Ord for RustTarget { - fn cmp(&self, other: &Self) -> Ordering { - match (self.minor(), other.minor()) { - (Some(a), Some(b)) => a.cmp(&b), - (Some(_), None) => Ordering::Less, - (None, Some(_)) => Ordering::Greater, - (None, None) => Ordering::Equal, + while i < targets.len() { + let (target, minor) = targets[i]; + + if earliest_minor > minor { + earliest_minor = minor; + earliest_target = Some(target); } + + i += 1; } + + match earliest_target { + Some(target) => target, + None => unreachable!(), + } +}; + +fn invalid_input(input: &str, msg: impl fmt::Display) -> io::Error { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("\"{input}\" is not a valid Rust target, {msg}"), + ) } impl FromStr for RustTarget { type Err = io::Error; - fn from_str(s: &str) -> Result { - if s == "nightly" { + fn from_str(input: &str) -> Result { + if input == "nightly" { return Ok(Self::Nightly); } - if let Some(("1", str_minor)) = s.split_once('.') { - if let Ok(minor) = str_minor.parse::() { - for (target, target_minor) in Self::stable_releases() { - if minor == target_minor { - return Ok(target); - } - } - } + let Some((major_str, tail)) = input.split_once('.') else { + return Err(invalid_input(input, "accepted values are of the form \"1.71\", \"1.71.1\" or \"nightly\"." ) ); + }; + + if major_str != "1" { + return Err(invalid_input( + input, + "The largest major version of Rust released is \"1\"", + )); } - Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Got an invalid Rust target. Accepted values are of the form \"1.71\" or \"nightly\"." - )) + let (minor, patch) = if let Some((minor_str, patch_str)) = + tail.split_once('.') + { + let Ok(minor) = minor_str.parse::() else { + return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer")); + }; + let Ok(patch) = patch_str.parse::() else { + return Err(invalid_input(input, "the patch version number must be an unsigned 64-bit integer")); + }; + (minor, patch) + } else { + let Ok(minor) = tail.parse::() else { + return Err(invalid_input(input, "the minor version number must be an unsigned 64-bit integer")); + }; + (minor, 0) + }; + + Self::stable(minor, patch).map_err(|err| invalid_input(input, err)) } } -impl std::fmt::Display for RustTarget { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.minor() { - Some(minor) => write!(f, "1.{}", minor), - None => "nightly".fmt(f), - } +impl RustFeatures { + /// Compute the features that must be enabled in a specific Rust target with the latest edition + /// available in that target. + pub(crate) fn new_with_latest_edition(target: RustTarget) -> Self { + Self::new(target, target.latest_edition()) } } impl Default for RustFeatures { fn default() -> Self { - RustTarget::default().into() + Self::new_with_latest_edition(RustTarget::default()) } } #[cfg(test)] mod test { - #![allow(unused_imports)] use super::*; #[test] - fn target_features() { - let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0); - assert!( - !f_1_0.static_lifetime_elision && - !f_1_0.core_ffi_c_void && - !f_1_0.untagged_union && - !f_1_0.associated_const && - !f_1_0.builtin_clone_impls && - !f_1_0.repr_align && - !f_1_0.thiscall_abi && - !f_1_0.vectorcall_abi + fn release_versions_for_editions() { + assert_eq!( + "1.51".parse::().unwrap().latest_edition(), + RustEdition::Edition2018 ); - let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21); - assert!( - f_1_21.static_lifetime_elision && - !f_1_21.core_ffi_c_void && - f_1_21.untagged_union && - f_1_21.associated_const && - f_1_21.builtin_clone_impls && - !f_1_21.repr_align && - !f_1_21.thiscall_abi && - !f_1_21.vectorcall_abi + assert_eq!( + "1.59".parse::().unwrap().latest_edition(), + RustEdition::Edition2021 ); - let features = RustFeatures::from(RustTarget::Stable_1_71); + assert_eq!( + "1.85".parse::().unwrap().latest_edition(), + RustEdition::Edition2024 + ); + assert_eq!( + "nightly".parse::().unwrap().latest_edition(), + RustEdition::Edition2024 + ); + } + + #[test] + fn target_features() { + let features = + RustFeatures::new_with_latest_edition(RustTarget::Stable_1_71); assert!( features.c_unwind_abi && features.abi_efiapi && !features.thiscall_abi ); - let f_nightly = RustFeatures::from(RustTarget::Nightly); + + let features = RustFeatures::new( + RustTarget::Stable_1_77, + RustEdition::Edition2018, + ); + assert!(!features.literal_cstr); + + let features = + RustFeatures::new_with_latest_edition(RustTarget::Stable_1_77); + assert!(features.literal_cstr); + + let f_nightly = + RustFeatures::new_with_latest_edition(RustTarget::Nightly); assert!( - f_nightly.static_lifetime_elision && - f_nightly.core_ffi_c_void && - f_nightly.untagged_union && - f_nightly.associated_const && - f_nightly.builtin_clone_impls && - f_nightly.maybe_uninit && - f_nightly.repr_align && - f_nightly.thiscall_abi && - f_nightly.vectorcall_abi + f_nightly.vectorcall_abi && + f_nightly.ptr_metadata && + f_nightly.layout_for_ptr ); } - fn test_target(target_str: &str, target: RustTarget) { - let target_string = target.to_string(); - assert_eq!(target_str, target_string); - assert_eq!(target, RustTarget::from_str(target_str).unwrap()); + fn test_target(input: &str, expected: RustTarget) { + // Two targets are equivalent if they enable the same set of features + let expected = RustFeatures::new_with_latest_edition(expected); + let found = RustFeatures::new_with_latest_edition( + input.parse::().unwrap(), + ); + assert_eq!( + expected, + found, + "target {input} enables features:\n{found:#?}\nand should enable features:\n{expected:#?}" + ); } + fn test_invalid_target(input: &str) { + assert!( + input.parse::().is_err(), + "{input} should be an invalid target" + ); + } + #[test] - fn str_to_target() { - test_target("1.0", RustTarget::Stable_1_0); - test_target("1.17", RustTarget::Stable_1_17); - test_target("1.19", RustTarget::Stable_1_19); - test_target("1.21", RustTarget::Stable_1_21); - test_target("1.25", RustTarget::Stable_1_25); + fn valid_targets() { test_target("1.71", RustTarget::Stable_1_71); + test_target("1.71.0", RustTarget::Stable_1_71); + test_target("1.71.1", RustTarget::Stable_1_71); + test_target("1.72", RustTarget::Stable_1_71); + test_target("1.73", RustTarget::Stable_1_73); + test_target("1.18446744073709551615", LATEST_STABLE_RUST); test_target("nightly", RustTarget::Nightly); + } + + #[test] + fn invalid_targets() { + test_invalid_target("2.0"); + test_invalid_target("1.cat"); + test_invalid_target("1.0.cat"); + test_invalid_target("1.18446744073709551616"); + test_invalid_target("1.0.18446744073709551616"); + test_invalid_target("1.-1.0"); + test_invalid_target("1.0.-1"); + test_invalid_target("beta"); + test_invalid_target("1.0.0"); + test_invalid_target("1.32.0"); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/derive.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/derive.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/derive.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/derive.rs Mon May 11 04:49:32 2026 @@ -104,7 +104,7 @@ } } -impl<'ctx> CannotDerive<'ctx> { +impl CannotDerive<'_> { fn insert>( &mut self, id: Id, @@ -112,10 +112,8 @@ ) -> ConstrainResult { let id = id.into(); trace!( - "inserting {:?} can_derive<{}>={:?}", - id, + "inserting {id:?} can_derive<{}>={can_derive:?}", self.derive_trait, - can_derive ); if let CanDerive::Yes = can_derive { @@ -168,7 +166,7 @@ return CanDerive::No; } - trace!("ty: {:?}", ty); + trace!("ty: {ty:?}"); if item.is_opaque(self.ctx, &()) { if !self.derive_trait.can_derive_union() && ty.is_union() && @@ -181,26 +179,11 @@ return CanDerive::No; } - let layout_can_derive = - ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { - l.opaque().array_size_within_derive_limit(self.ctx) - }); - - match layout_can_derive { - CanDerive::Yes => { - trace!( - " we can trivially derive {} for the layout", - self.derive_trait - ); - } - _ => { - trace!( - " we cannot derive {} for the layout", - self.derive_trait - ); - } - }; - return layout_can_derive; + trace!( + " we can trivially derive {} for the layout", + self.derive_trait + ); + return CanDerive::Yes; } match *ty.kind() { @@ -217,9 +200,7 @@ TypeKind::Reference(..) | TypeKind::ObjCInterface(..) | TypeKind::ObjCId | - TypeKind::ObjCSel => { - return self.derive_trait.can_derive_simple(ty.kind()); - } + TypeKind::ObjCSel => self.derive_trait.can_derive_simple(ty.kind()), TypeKind::Pointer(inner) => { let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); @@ -236,7 +217,7 @@ // Complex cases need more information TypeKind::Array(t, len) => { let inner_type = - self.can_derive.get(&t.into()).cloned().unwrap_or_default(); + self.can_derive.get(&t.into()).copied().unwrap_or_default(); if inner_type != CanDerive::Yes { trace!( " arrays of T for which we cannot derive {} \ @@ -275,7 +256,7 @@ } TypeKind::Vector(t, len) => { let inner_type = - self.can_derive.get(&t.into()).cloned().unwrap_or_default(); + self.can_derive.get(&t.into()).copied().unwrap_or_default(); if inner_type != CanDerive::Yes { trace!( " vectors of T for which we cannot derive {} \ @@ -342,26 +323,11 @@ return CanDerive::No; } - let layout_can_derive = - ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { - l.opaque() - .array_size_within_derive_limit(self.ctx) - }); - match layout_can_derive { - CanDerive::Yes => { - trace!( - " union layout can trivially derive {}", - self.derive_trait - ); - } - _ => { - trace!( - " union layout cannot derive {}", - self.derive_trait - ); - } - }; - return layout_can_derive; + trace!( + " union layout can trivially derive {}", + self.derive_trait + ); + return CanDerive::Yes; } } @@ -431,13 +397,13 @@ let can_derive = self.can_derive .get(&sub_id) - .cloned() + .copied() .unwrap_or_default(); match can_derive { - CanDerive::Yes => trace!(" member {:?} can derive {}", sub_id, self.derive_trait), - CanDerive::Manually => trace!(" member {:?} cannot derive {}, but it may be implemented", sub_id, self.derive_trait), - CanDerive::No => trace!(" member {:?} cannot derive {}", sub_id, self.derive_trait), + CanDerive::Yes => trace!(" member {sub_id:?} can derive {}", self.derive_trait), + CanDerive::Manually => trace!(" member {sub_id:?} cannot derive {}, but it may be implemented", self.derive_trait), + CanDerive::No => trace!(" member {sub_id:?} cannot derive {}", self.derive_trait), } *candidate.get_or_insert(CanDerive::Yes) |= can_derive; @@ -456,7 +422,7 @@ } impl DeriveTrait { - fn not_by_name(&self, ctx: &BindgenContext, item: &Item) -> bool { + fn not_by_name(self, ctx: &BindgenContext, item: &Item) -> bool { match self { DeriveTrait::Copy => ctx.no_copy_by_name(item), DeriveTrait::Debug => ctx.no_debug_by_name(item), @@ -468,21 +434,21 @@ } } - fn consider_edge_comp(&self) -> EdgePredicate { + fn consider_edge_comp(self) -> EdgePredicate { match self { DeriveTrait::PartialEqOrPartialOrd => consider_edge_default, _ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field), } } - fn consider_edge_typeref(&self) -> EdgePredicate { + fn consider_edge_typeref(self) -> EdgePredicate { match self { DeriveTrait::PartialEqOrPartialOrd => consider_edge_default, _ => |kind| kind == EdgeKind::TypeReference, } } - fn consider_edge_tmpl_inst(&self) -> EdgePredicate { + fn consider_edge_tmpl_inst(self) -> EdgePredicate { match self { DeriveTrait::PartialEqOrPartialOrd => consider_edge_default, _ => |kind| { @@ -494,31 +460,27 @@ } } - fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool { - if ctx.options().rust_features().larger_arrays { - !matches!(self, DeriveTrait::Default) - } else { - matches!(self, DeriveTrait::Copy) - } + fn can_derive_large_array(self, _: &BindgenContext) -> bool { + !matches!(self, DeriveTrait::Default) } - fn can_derive_union(&self) -> bool { + fn can_derive_union(self) -> bool { matches!(self, DeriveTrait::Copy) } - fn can_derive_compound_with_destructor(&self) -> bool { + fn can_derive_compound_with_destructor(self) -> bool { !matches!(self, DeriveTrait::Copy) } - fn can_derive_compound_with_vtable(&self) -> bool { + fn can_derive_compound_with_vtable(self) -> bool { !matches!(self, DeriveTrait::Default) } - fn can_derive_compound_forward_decl(&self) -> bool { + fn can_derive_compound_forward_decl(self) -> bool { matches!(self, DeriveTrait::Copy | DeriveTrait::Debug) } - fn can_derive_incomplete_array(&self) -> bool { + fn can_derive_incomplete_array(self) -> bool { !matches!( self, DeriveTrait::Copy | @@ -527,63 +489,60 @@ ) } - fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive { + fn can_derive_fnptr(self, f: &FunctionSig) -> CanDerive { match (self, f.function_pointers_can_derive()) { - (DeriveTrait::Copy, _) | (DeriveTrait::Default, _) | (_, true) => { - trace!(" function pointer can derive {}", self); + (DeriveTrait::Copy | DeriveTrait::Default, _) | (_, true) => { + trace!(" function pointer can derive {self}"); CanDerive::Yes } (DeriveTrait::Debug, false) => { - trace!(" function pointer cannot derive {}, but it may be implemented", self); + trace!(" function pointer cannot derive {self}, but it may be implemented"); CanDerive::Manually } (_, false) => { - trace!(" function pointer cannot derive {}", self); + trace!(" function pointer cannot derive {self}"); CanDerive::No } } } - fn can_derive_vector(&self) -> CanDerive { - match self { - DeriveTrait::PartialEqOrPartialOrd => { - // FIXME: vectors always can derive PartialEq, but they should - // not derive PartialOrd: - // https://github.com/rust-lang-nursery/packed_simd/issues/48 - trace!(" vectors cannot derive PartialOrd"); - CanDerive::No - } - _ => { - trace!(" vector can derive {}", self); - CanDerive::Yes - } + fn can_derive_vector(self) -> CanDerive { + if self == DeriveTrait::PartialEqOrPartialOrd { + // FIXME: vectors always can derive PartialEq, but they should + // not derive PartialOrd: + // https://github.com/rust-lang-nursery/packed_simd/issues/48 + trace!(" vectors cannot derive PartialOrd"); + CanDerive::No + } else { + trace!(" vector can derive {self}"); + CanDerive::Yes } } - fn can_derive_pointer(&self) -> CanDerive { - match self { - DeriveTrait::Default => { - trace!(" pointer cannot derive Default"); - CanDerive::No - } - _ => { - trace!(" pointer can derive {}", self); - CanDerive::Yes - } + fn can_derive_pointer(self) -> CanDerive { + if self == DeriveTrait::Default { + trace!(" pointer cannot derive Default"); + CanDerive::No + } else { + trace!(" pointer can derive {self}"); + CanDerive::Yes } } - fn can_derive_simple(&self, kind: &TypeKind) -> CanDerive { + fn can_derive_simple(self, kind: &TypeKind) -> CanDerive { match (self, kind) { // === Default === - (DeriveTrait::Default, TypeKind::Void) | - (DeriveTrait::Default, TypeKind::NullPtr) | - (DeriveTrait::Default, TypeKind::Enum(..)) | - (DeriveTrait::Default, TypeKind::Reference(..)) | - (DeriveTrait::Default, TypeKind::TypeParam) | - (DeriveTrait::Default, TypeKind::ObjCInterface(..)) | - (DeriveTrait::Default, TypeKind::ObjCId) | - (DeriveTrait::Default, TypeKind::ObjCSel) => { + ( + DeriveTrait::Default, + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::TypeParam | + TypeKind::ObjCInterface(..) | + TypeKind::ObjCId | + TypeKind::ObjCSel, + ) => { trace!(" types that always cannot derive Default"); CanDerive::No } @@ -593,14 +552,16 @@ ) } // === Hash === - (DeriveTrait::Hash, TypeKind::Float(..)) | - (DeriveTrait::Hash, TypeKind::Complex(..)) => { + ( + DeriveTrait::Hash, + TypeKind::Float(..) | TypeKind::Complex(..), + ) => { trace!(" float cannot derive Hash"); CanDerive::No } // === others === _ => { - trace!(" simple type that can always derive {}", self); + trace!(" simple type that can always derive {self}"); CanDerive::Yes } } @@ -645,7 +606,7 @@ self.ctx .allowlisted_items() .iter() - .cloned() + .copied() .flat_map(|i| { let mut reachable = vec![i]; i.trace( @@ -661,9 +622,9 @@ } fn constrain(&mut self, id: ItemId) -> ConstrainResult { - trace!("constrain: {:?}", id); + trace!("constrain: {id:?}"); - if let Some(CanDerive::No) = self.can_derive.get(&id).cloned() { + if let Some(CanDerive::No) = self.can_derive.get(&id) { trace!(" already know it cannot derive {}", self.derive_trait); return ConstrainResult::Same; } @@ -676,7 +637,7 @@ let is_reached_limit = |l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT; if !self.derive_trait.can_derive_large_array(self.ctx) && - ty.layout(self.ctx).map_or(false, is_reached_limit) + ty.layout(self.ctx).is_some_and(is_reached_limit) { // We have to be conservative: the struct *could* have enough // padding that we emit an array that is longer than @@ -700,7 +661,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } @@ -727,6 +688,6 @@ ) -> HashSet { can_derive .into_iter() - .filter_map(|(k, v)| if v != CanDerive::Yes { Some(k) } else { None }) + .filter_map(|(k, v)| if v == CanDerive::Yes { None } else { Some(k) }) .collect() } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_destructor.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_destructor.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_destructor.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_destructor.rs Mon May 11 04:49:32 2026 @@ -39,7 +39,7 @@ dependencies: HashMap>, } -impl<'ctx> HasDestructorAnalysis<'ctx> { +impl HasDestructorAnalysis<'_> { fn consider_edge(kind: EdgeKind) -> bool { // These are the only edges that can affect whether a type has a // destructor or not. @@ -58,9 +58,8 @@ let was_not_already_in_set = self.have_destructor.insert(id); assert!( was_not_already_in_set, - "We shouldn't try and insert {:?} twice because if it was \ - already in the set, `constrain` should have exited early.", - id + "We shouldn't try and insert {id:?} twice because if it was \ + already in the set, `constrain` should have exited early." ); ConstrainResult::Changed } @@ -83,7 +82,7 @@ } fn initial_worklist(&self) -> Vec { - self.ctx.allowlisted_items().iter().cloned().collect() + self.ctx.allowlisted_items().iter().copied().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { @@ -94,9 +93,8 @@ } let item = self.ctx.resolve_item(id); - let ty = match item.as_type() { - None => return ConstrainResult::Same, - Some(ty) => ty, + let Some(ty) = item.as_type() else { + return ConstrainResult::Same; }; match *ty.kind() { @@ -162,7 +160,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_float.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_float.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_float.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_float.rs Mon May 11 04:49:32 2026 @@ -39,7 +39,7 @@ dependencies: HashMap>, } -impl<'ctx> HasFloat<'ctx> { +impl HasFloat<'_> { fn consider_edge(kind: EdgeKind) -> bool { match kind { EdgeKind::BaseMember | @@ -56,21 +56,20 @@ EdgeKind::FunctionParameter | EdgeKind::InnerType | EdgeKind::InnerVar | - EdgeKind::Method => false, + EdgeKind::Method | EdgeKind::Generic => false, } } fn insert>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); - trace!("inserting {:?} into the has_float set", id); + trace!("inserting {id:?} into the has_float set"); let was_not_already_in_set = self.has_float.insert(id); assert!( was_not_already_in_set, - "We shouldn't try and insert {:?} twice because if it was \ - already in the set, `constrain` should have exited early.", - id + "We shouldn't try and insert {id:?} twice because if it was \ + already in the set, `constrain` should have exited early." ); ConstrainResult::Changed @@ -94,11 +93,11 @@ } fn initial_worklist(&self) -> Vec { - self.ctx.allowlisted_items().iter().cloned().collect() + self.ctx.allowlisted_items().iter().copied().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { - trace!("constrain: {:?}", id); + trace!("constrain: {id:?}"); if self.has_float.contains(&id) { trace!(" already know it do not have float"); @@ -106,12 +105,9 @@ } let item = self.ctx.resolve_item(id); - let ty = match item.as_type() { - Some(ty) => ty, - None => { - trace!(" not a type; ignoring"); - return ConstrainResult::Same; - } + let Some(ty) = item.as_type() else { + trace!(" not a type; ignoring"); + return ConstrainResult::Same; }; match *ty.kind() { @@ -210,7 +206,7 @@ if args_have { trace!( " template args have float, so \ - insantiation also has float" + instantiation also has float" ); return self.insert(id); } @@ -221,7 +217,7 @@ if def_has { trace!( " template definition has float, so \ - insantiation also has" + instantiation also has" ); return self.insert(id); } @@ -238,7 +234,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_type_param_in_array.rs Mon May 11 04:49:32 2026 @@ -17,7 +17,7 @@ /// * If T is a type alias, a templated alias or an indirection to another type, /// it has type parameter in array if the type T refers to has. /// * If T is a compound type, it has array if any of base memter or field -/// has type paramter in array. +/// has type parameter in array. /// * If T is an instantiation of an abstract template definition, T has /// type parameter in array if any of the template arguments or template definition /// has. @@ -39,7 +39,7 @@ dependencies: HashMap>, } -impl<'ctx> HasTypeParameterInArray<'ctx> { +impl HasTypeParameterInArray<'_> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // These are the only edges that can affect whether a type has type parameter @@ -58,25 +58,21 @@ EdgeKind::FunctionParameter | EdgeKind::InnerType | EdgeKind::InnerVar | - EdgeKind::Method => false, + EdgeKind::Method | EdgeKind::Generic => false, } } fn insert>(&mut self, id: Id) -> ConstrainResult { let id = id.into(); - trace!( - "inserting {:?} into the has_type_parameter_in_array set", - id - ); + trace!("inserting {id:?} into the has_type_parameter_in_array set"); let was_not_already_in_set = self.has_type_parameter_in_array.insert(id); assert!( was_not_already_in_set, - "We shouldn't try and insert {:?} twice because if it was \ - already in the set, `constrain` should have exited early.", - id + "We shouldn't try and insert {id:?} twice because if it was \ + already in the set, `constrain` should have exited early." ); ConstrainResult::Changed @@ -100,11 +96,11 @@ } fn initial_worklist(&self) -> Vec { - self.ctx.allowlisted_items().iter().cloned().collect() + self.ctx.allowlisted_items().iter().copied().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { - trace!("constrain: {:?}", id); + trace!("constrain: {id:?}"); if self.has_type_parameter_in_array.contains(&id) { trace!(" already know it do not have array"); @@ -112,12 +108,9 @@ } let item = self.ctx.resolve_item(id); - let ty = match item.as_type() { - Some(ty) => ty, - None => { - trace!(" not a type; ignoring"); - return ConstrainResult::Same; - } + let Some(ty) = item.as_type() else { + trace!(" not a type; ignoring"); + return ConstrainResult::Same; }; match *ty.kind() { @@ -146,17 +139,14 @@ TypeKind::Array(t, _) => { let inner_ty = self.ctx.resolve_type(t).canonical_type(self.ctx); - match *inner_ty.kind() { - TypeKind::TypeParam => { - trace!(" Array with Named type has type parameter"); - self.insert(id) - } - _ => { - trace!( - " Array without Named type does have type parameter" - ); - ConstrainResult::Same - } + if let TypeKind::TypeParam = *inner_ty.kind() { + trace!(" Array with Named type has type parameter"); + self.insert(id) + } else { + trace!( + " Array without Named type does have type parameter" + ); + ConstrainResult::Same } } @@ -210,7 +200,7 @@ if args_have { trace!( " template args have array, so \ - insantiation also has array" + instantiation also has array" ); return self.insert(id); } @@ -221,7 +211,7 @@ if def_has { trace!( " template definition has array, so \ - insantiation also has" + instantiation also has" ); return self.insert(id); } @@ -238,7 +228,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_vtable.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_vtable.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/has_vtable.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/has_vtable.rs Mon May 11 04:49:32 2026 @@ -9,9 +9,10 @@ use std::ops; /// The result of the `HasVtableAnalysis` for an individual item. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub(crate) enum HasVtableResult { /// The item does not have a vtable pointer. + #[default] No, /// The item has a vtable and the actual vtable pointer is within this item. @@ -22,12 +23,6 @@ BaseHasVtable, } -impl Default for HasVtableResult { - fn default() -> Self { - HasVtableResult::No - } -} - impl HasVtableResult { /// Take the least upper bound of `self` and `rhs`. pub(crate) fn join(self, rhs: Self) -> Self { @@ -45,7 +40,7 @@ impl ops::BitOrAssign for HasVtableResult { fn bitor_assign(&mut self, rhs: HasVtableResult) { - *self = self.join(rhs) + *self = self.join(rhs); } } @@ -77,7 +72,7 @@ dependencies: HashMap>, } -impl<'ctx> HasVtableAnalysis<'ctx> { +impl HasVtableAnalysis<'_> { fn consider_edge(kind: EdgeKind) -> bool { // These are the only edges that can affect whether a type has a // vtable or not. @@ -123,9 +118,9 @@ let from = from.into(); let to = to.into(); - match self.have_vtable.get(&from).cloned() { + match self.have_vtable.get(&from) { None => ConstrainResult::Same, - Some(r) => self.insert(to, r), + Some(r) => self.insert(to, *r), } } } @@ -147,16 +142,15 @@ } fn initial_worklist(&self) -> Vec { - self.ctx.allowlisted_items().iter().cloned().collect() + self.ctx.allowlisted_items().iter().copied().collect() } fn constrain(&mut self, id: ItemId) -> ConstrainResult { - trace!("constrain {:?}", id); + trace!("constrain {id:?}"); let item = self.ctx.resolve_item(id); - let ty = match item.as_type() { - None => return ConstrainResult::Same, - Some(ty) => ty, + let Some(ty) = item.as_type() else { + return ConstrainResult::Same; }; // TODO #851: figure out a way to handle deriving from template type parameters. @@ -181,7 +175,7 @@ } let bases_has_vtable = info.base_members().iter().any(|base| { - trace!(" comp has a base with a vtable: {:?}", base); + trace!(" comp has a base with a vtable: {base:?}"); self.have_vtable.contains_key(&base.ty.into()) }); if bases_has_vtable { @@ -205,7 +199,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } @@ -228,7 +222,7 @@ /// vtable during codegen. /// /// This is not for _computing_ whether the thing has a vtable, it is for -/// looking up the results of the HasVtableAnalysis's computations for a +/// looking up the results of the `HasVtableAnalysis`'s computations for a /// specific thing. pub(crate) trait HasVtable { /// Return `true` if this thing has vtable, `false` otherwise. diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/mod.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/mod.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/mod.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/mod.rs Mon May 11 04:49:32 2026 @@ -125,22 +125,17 @@ /// Whether an analysis's `constrain` function modified the incremental results /// or not. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub(crate) enum ConstrainResult { /// The incremental results were updated, and the fix-point computation /// should continue. Changed, /// The incremental results were not updated. + #[default] Same, } -impl Default for ConstrainResult { - fn default() -> Self { - ConstrainResult::Same - } -} - impl ops::BitOr for ConstrainResult { type Output = Self; @@ -216,7 +211,7 @@ #[cfg(test)] mod tests { use super::*; - use crate::{HashMap, HashSet}; + use crate::HashSet; // Here we find the set of nodes that are reachable from any given // node. This is a lattice mapping nodes to subsets of all nodes. Our join @@ -285,9 +280,9 @@ fn reverse(&self) -> Graph { let mut reversed = Graph::default(); - for (node, edges) in self.0.iter() { + for (node, edges) in &self.0 { reversed.0.entry(*node).or_insert_with(Vec::new); - for referent in edges.iter() { + for referent in edges { reversed .0 .entry(*referent) @@ -311,7 +306,7 @@ type Extra = &'a Graph; type Output = HashMap>; - fn new(graph: &'a Graph) -> ReachableFrom { + fn new(graph: &'a Graph) -> Self { let reversed = graph.reverse(); ReachableFrom { reachable: Default::default(), @@ -321,7 +316,7 @@ } fn initial_worklist(&self) -> Vec { - self.graph.0.keys().cloned().collect() + self.graph.0.keys().copied().collect() } fn constrain(&mut self, node: Node) -> ConstrainResult { @@ -336,7 +331,7 @@ let original_size = self.reachable.entry(node).or_default().len(); - for sub_node in self.graph.0[&node].iter() { + for sub_node in &self.graph.0[&node] { self.reachable.get_mut(&node).unwrap().insert(*sub_node); let sub_reachable = @@ -348,10 +343,10 @@ } let new_size = self.reachable[&node].len(); - if original_size != new_size { - ConstrainResult::Changed - } else { + if original_size == new_size { ConstrainResult::Same + } else { + ConstrainResult::Changed } } @@ -359,7 +354,7 @@ where F: FnMut(Node), { - for dep in self.reversed.0[&node].iter() { + for dep in &self.reversed.0[&node] { f(*dep); } } @@ -375,13 +370,13 @@ fn monotone() { let g = Graph::make_test_graph(); let reachable = analyze::(&g); - println!("reachable = {:#?}", reachable); + println!("reachable = {reachable:#?}"); fn nodes(nodes: A) -> HashSet where A: AsRef<[usize]>, { - nodes.as_ref().iter().cloned().map(Node).collect() + nodes.as_ref().iter().copied().map(Node).collect() } let mut expected = HashMap::default(); @@ -393,7 +388,7 @@ expected.insert(Node(6), nodes([8])); expected.insert(Node(7), nodes([3, 4, 5, 6, 7, 8])); expected.insert(Node(8), nodes([])); - println!("expected = {:#?}", expected); + println!("expected = {expected:#?}"); assert_eq!(reachable, expected); } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/sizedness.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/sizedness.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/sizedness.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/sizedness.rs Mon May 11 04:49:32 2026 @@ -24,13 +24,14 @@ /// /// We initially assume that all types are `ZeroSized` and then update our /// understanding as we learn more about each type. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub(crate) enum SizednessResult { /// The type is zero-sized. /// /// This means that if it is a C++ type, and is not being used as a base /// member, then we must add an `_address` byte to enforce the /// unique-address-per-distinct-object-instance rule. + #[default] ZeroSized, /// Whether this type is zero-sized or not depends on whether a type @@ -62,12 +63,6 @@ NonZeroSized, } -impl Default for SizednessResult { - fn default() -> Self { - SizednessResult::ZeroSized - } -} - impl SizednessResult { /// Take the least upper bound of `self` and `rhs`. pub(crate) fn join(self, rhs: Self) -> Self { @@ -85,20 +80,20 @@ impl ops::BitOrAssign for SizednessResult { fn bitor_assign(&mut self, rhs: SizednessResult) { - *self = self.join(rhs) + *self = self.join(rhs); } } /// An analysis that computes the sizedness of all types. /// /// * For types with known sizes -- for example pointers, scalars, etc... -- -/// they are assigned `NonZeroSized`. +/// they are assigned `NonZeroSized`. /// /// * For compound structure types with one or more fields, they are assigned -/// `NonZeroSized`. +/// `NonZeroSized`. /// /// * For compound structure types without any fields, the results of the bases -/// are `join`ed. +/// are `join`ed. /// /// * For type parameters, `DependsOnTypeParam` is assigned. #[derive(Debug)] @@ -110,7 +105,7 @@ sized: HashMap, } -impl<'ctx> SizednessAnalysis<'ctx> { +impl SizednessAnalysis<'_> { fn consider_edge(kind: EdgeKind) -> bool { // These are the only edges that can affect whether a type is // zero-sized or not. @@ -132,7 +127,7 @@ id: TypeId, result: SizednessResult, ) -> ConstrainResult { - trace!("inserting {:?} for {:?}", result, id); + trace!("inserting {result:?} for {id:?}"); if let SizednessResult::ZeroSized = result { return ConstrainResult::Same; @@ -155,9 +150,9 @@ } fn forward(&mut self, from: TypeId, to: TypeId) -> ConstrainResult { - match self.sized.get(&from).cloned() { + match self.sized.get(&from) { None => ConstrainResult::Same, - Some(r) => self.insert(to, r), + Some(r) => self.insert(to, *r), } } } @@ -196,17 +191,14 @@ self.ctx .allowlisted_items() .iter() - .cloned() .filter_map(|id| id.as_type_id(self.ctx)) .collect() } fn constrain(&mut self, id: TypeId) -> ConstrainResult { - trace!("constrain {:?}", id); + trace!("constrain {id:?}"); - if let Some(SizednessResult::NonZeroSized) = - self.sized.get(&id).cloned() - { + if let Some(SizednessResult::NonZeroSized) = self.sized.get(&id) { trace!(" already know it is not zero-sized"); return ConstrainResult::Same; } @@ -327,7 +319,7 @@ { if let Some(edges) = self.dependencies.get(&id) { for ty in edges { - trace!("enqueue {:?} into worklist", ty); + trace!("enqueue {ty:?} into worklist"); f(*ty); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/template_params.rs firefox-140.10.2/third_party/rust/bindgen/ir/analysis/template_params.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/analysis/template_params.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/analysis/template_params.rs Mon May 11 04:49:32 2026 @@ -124,8 +124,8 @@ /// ``` /// /// * Finally, for all other IR item kinds, we use our lattice's `join` -/// operation: set union with each successor of the given item's template -/// parameter usage: +/// operation: set union with each successor of the given item's template +/// parameter usage: /// /// ```ignore /// template_param_usage(v) = @@ -161,7 +161,7 @@ allowlisted_items: HashSet, } -impl<'ctx> UsedTemplateParameters<'ctx> { +impl UsedTemplateParameters<'_> { fn consider_edge(kind: EdgeKind) -> bool { match kind { // For each of these kinds of edges, if the referent uses a template @@ -259,7 +259,6 @@ a's used template param set should be `Some`", ) .iter() - .cloned() }); used_by_this_id.extend(args); @@ -291,10 +290,8 @@ for (arg, param) in args.iter().zip(params.iter()) { trace!( - " instantiation's argument {:?} is used if definition's \ - parameter {:?} is used", - arg, - param + " instantiation's argument {arg:?} is used if definition's \ + parameter {param:?} is used", ); if used_by_def.contains(¶m.into()) { @@ -322,8 +319,7 @@ arg's used template param set should be \ `Some`", ) - .iter() - .cloned(); + .iter(); used_by_this_id.extend(used_by_arg); } } @@ -355,12 +351,10 @@ sub_id's used template param set should be \ `Some`", ) - .iter() - .cloned(); + .iter(); trace!( - " union with {:?}'s usage: {:?}", - sub_id, + " union with {sub_id:?}'s usage: {:?}", used_by_sub_id.clone().collect::>() ); @@ -380,11 +374,11 @@ let mut used = HashMap::default(); let mut dependencies = HashMap::default(); let allowlisted_items: HashSet<_> = - ctx.allowlisted_items().iter().cloned().collect(); + ctx.allowlisted_items().iter().copied().collect(); let allowlisted_and_blocklisted_items: ItemSet = allowlisted_items .iter() - .cloned() + .copied() .flat_map(|i| { let mut reachable = vec![i]; i.trace( @@ -470,7 +464,7 @@ // (This is so that every item we call `constrain` on is guaranteed // to have a set of template parameters, and we can allow // blocklisted templates to use all of their parameters). - for item in allowlisted_items.iter() { + for item in &allowlisted_items { extra_assert!(used.contains_key(item)); extra_assert!(dependencies.contains_key(item)); item.trace( @@ -480,7 +474,7 @@ extra_assert!(dependencies.contains_key(&sub_item)); }, &(), - ) + ); } } @@ -498,7 +492,7 @@ self.ctx .allowlisted_items() .iter() - .cloned() + .copied() .flat_map(|i| { let mut reachable = vec![i]; i.trace( @@ -524,8 +518,8 @@ // an analog to slice::split_at_mut. let mut used_by_this_id = self.take_this_id_usage_set(id); - trace!("constrain {:?}", id); - trace!(" initially, used set is {:?}", used_by_this_id); + trace!("constrain {id:?}"); + trace!(" initially, used set is {used_by_this_id:?}"); let original_len = used_by_this_id.len(); @@ -562,7 +556,7 @@ _ => self.constrain_join(&mut used_by_this_id, item), } - trace!(" finally, used set is {:?}", used_by_this_id); + trace!(" finally, used set is {used_by_this_id:?}"); let new_len = used_by_this_id.len(); assert!( @@ -576,10 +570,10 @@ self.used.insert(id, Some(used_by_this_id)); extra_assert!(self.used.values().all(|v| v.is_some())); - if new_len != original_len { - ConstrainResult::Changed - } else { + if new_len == original_len { ConstrainResult::Same + } else { + ConstrainResult::Changed } } @@ -589,7 +583,7 @@ { if let Some(edges) = self.dependencies.get(&item) { for item in edges { - trace!("enqueue {:?} into worklist", item); + trace!("enqueue {item:?} into worklist"); f(*item); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/annotations.rs firefox-140.10.2/third_party/rust/bindgen/ir/annotations.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/annotations.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/annotations.rs Mon May 11 04:49:32 2026 @@ -8,14 +8,15 @@ use crate::clang; -/// What kind of visibility modifer should be used for a struct or field? -#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] +/// What kind of visibility modifier should be used for a struct or field? +#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Default)] pub enum FieldVisibilityKind { /// Fields are marked as private, i.e., struct Foo {bar: bool} Private, /// Fields are marked as crate public, i.e., struct Foo {pub(crate) bar: bool} PublicCrate, /// Fields are marked as public, i.e., struct Foo {pub bar: bool} + #[default] Public, } @@ -27,7 +28,7 @@ "private" => Ok(Self::Private), "crate" => Ok(Self::PublicCrate), "public" => Ok(Self::Public), - _ => Err(format!("Invalid visibility kind: `{}`", s)), + _ => Err(format!("Invalid visibility kind: `{s}`")), } } } @@ -44,12 +45,6 @@ } } -impl Default for FieldVisibilityKind { - fn default() -> Self { - FieldVisibilityKind::Public - } -} - /// What kind of accessor should we provide for a field? #[derive(Copy, PartialEq, Eq, Clone, Debug)] pub(crate) enum FieldAccessorKind { @@ -107,6 +102,8 @@ constify_enum_variant: bool, /// List of explicit derives for this type. derives: Vec, + /// List of explicit attributes for this type. + attributes: Vec, } fn parse_accessor(s: &str) -> FieldAccessorKind { @@ -174,6 +171,11 @@ &self.derives } + /// The list of attributes that have been specified in this annotation. + pub(crate) fn attributes(&self) -> &[String] { + &self.attributes + } + /// Should we avoid implementing the `Copy` trait? pub(crate) fn disallow_copy(&self) -> bool { self.disallow_copy @@ -211,7 +213,7 @@ comment .get_tag_attrs() .next() - .map_or(false, |attr| attr.name == "rustbindgen") + .is_some_and(|attr| attr.name == "rustbindgen") { *matched = true; for attr in comment.get_tag_attrs() { @@ -225,18 +227,19 @@ "replaces" => { self.use_instead_of = Some( attr.value.split("::").map(Into::into).collect(), - ) + ); } "derive" => self.derives.push(attr.value), + "attribute" => self.attributes.push(attr.value), "private" => { - self.visibility_kind = if attr.value != "false" { - Some(FieldVisibilityKind::Private) - } else { + self.visibility_kind = if attr.value == "false" { Some(FieldVisibilityKind::Public) + } else { + Some(FieldVisibilityKind::Private) }; } "accessor" => { - self.accessor_kind = Some(parse_accessor(&attr.value)) + self.accessor_kind = Some(parse_accessor(&attr.value)); } "constant" => self.constify_enum_variant = true, _ => {} diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/comment.rs firefox-140.10.2/third_party/rust/bindgen/ir/comment.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/comment.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/comment.rs Mon May 11 04:49:32 2026 @@ -13,7 +13,7 @@ /// Preprocesses a C/C++ comment so that it is a valid Rust comment. pub(crate) fn preprocess(comment: &str) -> String { - match self::kind(comment) { + match kind(comment) { Some(Kind::SingleLines) => preprocess_single_lines(comment), Some(Kind::MultiLine) => preprocess_multi_line(comment), None => comment.to_owned(), @@ -58,7 +58,7 @@ .collect(); // Remove the trailing line corresponding to the `*/`. - if lines.last().map_or(false, |l| l.trim().is_empty()) { + if lines.last().is_some_and(|l| l.trim().is_empty()) { lines.pop(); } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/comp.rs firefox-140.10.2/third_party/rust/bindgen/ir/comp.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/comp.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/comp.rs Mon May 11 04:49:32 2026 @@ -12,7 +12,7 @@ use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; use crate::clang; -use crate::codegen::struct_layout::{align_to, bytes_from_bits_pow2}; +use crate::codegen::struct_layout::align_to; use crate::ir::derive::CanDeriveCopy; use crate::parse::ParseError; use crate::HashMap; @@ -56,16 +56,16 @@ impl MethodKind { /// Is this a destructor method? - pub(crate) fn is_destructor(&self) -> bool { + pub(crate) fn is_destructor(self) -> bool { matches!( - *self, + self, MethodKind::Destructor | MethodKind::VirtualDestructor { .. } ) } /// Is this a pure virtual method? - pub(crate) fn is_pure_virtual(&self) -> bool { - match *self { + pub(crate) fn is_pure_virtual(self) -> bool { + match self { MethodKind::Virtual { pure_virtual } | MethodKind::VirtualDestructor { pure_virtual } => pure_virtual, _ => false, @@ -147,7 +147,7 @@ /// If this is a bitfield, how many bits does it need? fn bitfield_width(&self) -> Option; - /// Is this feild declared public? + /// Is this field declared public? fn is_public(&self) -> bool; /// Get the annotations for this field. @@ -361,7 +361,7 @@ "`Bitfield::getter_name` called on anonymous field" ); self.getter_name.as_ref().expect( - "`Bitfield::getter_name` should only be called after\ + "`Bitfield::getter_name` should only be called after \ assigning bitfield accessor names", ) } @@ -376,7 +376,7 @@ "`Bitfield::setter_name` called on anonymous field" ); self.setter_name.as_ref().expect( - "`Bitfield::setter_name` should only be called\ + "`Bitfield::setter_name` should only be called \ after assigning bitfield accessor names", ) } @@ -560,18 +560,12 @@ fields: &mut E, bitfield_unit_count: &mut usize, unit_size_in_bits: usize, - unit_align_in_bits: usize, bitfields: Vec, - packed: bool, ) where E: Extend, { *bitfield_unit_count += 1; - let align = if packed { - 1 - } else { - bytes_from_bits_pow2(unit_align_in_bits) - }; + let align = 1; let size = align_to(unit_size_in_bits, 8) / 8; let layout = Layout::new(size, align); fields.extend(Some(Field::Bitfields(BitfieldUnit { @@ -581,70 +575,45 @@ }))); } + // The offset we're in inside the struct, if we know it (we might not know it in presence of + // templates). + let mut start_offset_in_struct = 0; let mut max_align = 0; - let mut unfilled_bits_in_unit = 0; let mut unit_size_in_bits = 0; - let mut unit_align = 0; let mut bitfields_in_unit = vec![]; - // TODO(emilio): Determine this from attributes or pragma ms_struct - // directives. Also, perhaps we should check if the target is MSVC? - const is_ms_struct: bool = false; - + // TODO(emilio): Deal with ms_struct bitfield layout for MSVC? for bitfield in raw_bitfields { let bitfield_width = bitfield.bitfield_width().unwrap() as usize; let bitfield_layout = ctx.resolve_type(bitfield.ty()).layout(ctx).ok_or(())?; - let bitfield_size = bitfield_layout.size; let bitfield_align = bitfield_layout.align; + let bitfield_size = bitfield_layout.size; - let mut offset = unit_size_in_bits; - if !packed { - if is_ms_struct { - if unit_size_in_bits != 0 && - (bitfield_width == 0 || - bitfield_width > unfilled_bits_in_unit) - { - // We've reached the end of this allocation unit, so flush it - // and its bitfields. - unit_size_in_bits = - align_to(unit_size_in_bits, unit_align * 8); - flush_allocation_unit( - fields, - bitfield_unit_count, - unit_size_in_bits, - unit_align, - mem::take(&mut bitfields_in_unit), - packed, - ); + if unit_size_in_bits == 0 { + start_offset_in_struct = bitfield.offset().unwrap_or(0); + } - // Now we're working on a fresh bitfield allocation unit, so reset - // the current unit size and alignment. - offset = 0; - unit_align = 0; - } - } else if offset != 0 && - (bitfield_width == 0 || - (offset & (bitfield_align * 8 - 1)) + bitfield_width > - bitfield_size * 8) - { - offset = align_to(offset, bitfield_align * 8); - } + let mut offset_in_struct = + bitfield.offset().unwrap_or(unit_size_in_bits); + + // A zero-width field serves as alignment / padding. + if !packed && + offset_in_struct != 0 && + (bitfield_width == 0 || + (offset_in_struct & (bitfield_align * 8 - 1)) + + bitfield_width > + bitfield_size * 8) + { + offset_in_struct = align_to(offset_in_struct, bitfield_align * 8); } - // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not - // affect the alignment of a structure or union". This makes sense: such - // bit-fields are only used for padding, and we can't perform an - // un-aligned read of something we can't read because we can't even name - // it. + // According to the x86[-64] ABI spec: "Unnamed bit-fields’ types do not affect the + // alignment of a structure or union". This makes sense: such bit-fields are only used for + // padding, and we can't perform an un-aligned read of something we can't read because we + // can't even name it. if bitfield.name().is_some() { max_align = cmp::max(max_align, bitfield_align); - - // NB: The `bitfield_width` here is completely, absolutely - // intentional. Alignment of the allocation unit is based on the - // maximum bitfield width, not (directly) on the bitfields' types' - // alignment. - unit_align = cmp::max(unit_align, bitfield_width); } // Always keep all bitfields around. While unnamed bitifields are used @@ -652,15 +621,12 @@ // bitfields over their types size cause weird allocation size behavior from clang. // Therefore, all bitfields needed to be kept around in order to check for this // and make the struct opaque in this case - bitfields_in_unit.push(Bitfield::new(offset, bitfield)); - - unit_size_in_bits = offset + bitfield_width; - - // Compute what the physical unit's final size would be given what we - // have seen so far, and use that to compute how many bits are still - // available in the unit. - let data_size = align_to(unit_size_in_bits, bitfield_align * 8); - unfilled_bits_in_unit = data_size - unit_size_in_bits; + bitfields_in_unit.push(Bitfield::new( + offset_in_struct - start_offset_in_struct, + bitfield, + )); + unit_size_in_bits = + offset_in_struct - start_offset_in_struct + bitfield_width; } if unit_size_in_bits != 0 { @@ -669,9 +635,7 @@ fields, bitfield_unit_count, unit_size_in_bits, - unit_align, bitfields_in_unit, - packed, ); } @@ -782,7 +746,7 @@ getter }; let setter = { - let setter = format!("set_{}", bitfield_name); + let setter = format!("set_{bitfield_name}"); let mut setter = ctx.rust_mangle(&setter).to_string(); if has_method(methods, ctx, &setter) { setter.push_str("_bindgen_bitfield"); @@ -803,9 +767,8 @@ anon_field_counter += 1; *name = Some(format!( - "{}{}", + "{}{anon_field_counter}", ctx.options().anon_fields_prefix, - anon_field_counter )); } Field::Bitfields(ref mut bu) => { @@ -825,6 +788,23 @@ } } } + + /// Return the flex array member for the struct/class, if any. + fn flex_array_member(&self, ctx: &BindgenContext) -> Option { + let fields = match self { + CompFields::Before(_) => panic!("raw fields"), + CompFields::After { fields, .. } => fields, + CompFields::Error => return None, // panic? + }; + + match fields.last()? { + Field::Bitfields(..) => None, + Field::DataMember(FieldData { ty, .. }) => ctx + .resolve_type(*ty) + .is_incomplete_array(ctx) + .map(|item| item.expect_type_id(ctx)), + } + } } impl Trace for CompFields { @@ -931,7 +911,7 @@ pub(crate) kind: BaseKind, /// Name of the field in which this base should be stored. pub(crate) field_name: String, - /// Whether this base is inherited from publically. + /// Whether this base is inherited from publicly. pub(crate) is_pub: bool, } @@ -961,7 +941,7 @@ true } - /// Whether this base is inherited from publically. + /// Whether this base is inherited from publicly. pub(crate) fn is_public(&self) -> bool { self.is_pub } @@ -1001,6 +981,7 @@ /// The inner types that were declared inside this class, in something like: /// + /// ```c++ /// class Foo { /// typedef int FooTy; /// struct Bar { @@ -1009,6 +990,7 @@ /// } /// /// static Foo::Bar const = {3}; + /// ``` inner_types: Vec, /// Set of static constants declared inside this class. @@ -1027,7 +1009,7 @@ has_nonempty_base: bool, /// If this type has a template parameter which is not a type (e.g.: a - /// size_t) + /// `size_t`) has_non_type_template_params: bool, /// Whether this type has a bit field member whose width couldn't be @@ -1040,7 +1022,7 @@ /// Used to know if we've found an opaque attribute that could cause us to /// generate a type with invalid layout. This is explicitly used to avoid us - /// generating bad alignments when parsing types like max_align_t. + /// generating bad alignments when parsing types like `max_align_t`. /// /// It's not clear what the behavior should be here, if generating the item /// and pray, or behave as an opaque type. @@ -1082,7 +1064,7 @@ /// /// If we're a union without known layout, we try to compute it from our /// members. This is not ideal, but clang fails to report the size for these - /// kind of unions, see test/headers/template_union.hpp + /// kind of unions, see `test/headers/template_union.hpp` pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option { // We can't do better than clang here, sorry. if self.kind == CompKind::Struct { @@ -1122,6 +1104,14 @@ } } + /// Return the flex array member and its element type if any + pub(crate) fn flex_array_member( + &self, + ctx: &BindgenContext, + ) -> Option { + self.fields.flex_array_member(ctx) + } + fn has_fields(&self) -> bool { match self.fields { CompFields::Error => false, @@ -1138,14 +1128,14 @@ match self.fields { CompFields::Error => {} CompFields::After { ref fields, .. } => { - for field in fields.iter() { + for field in fields { if let Some(layout) = field.layout(ctx) { callback(layout); } } } CompFields::Before(ref raw_fields) => { - for field in raw_fields.iter() { + for field in raw_fields { let field_ty = ctx.resolve_type(field.0.ty); if let Some(layout) = field_ty.layout(ctx) { callback(layout); @@ -1155,7 +1145,8 @@ } } - fn has_bitfields(&self) -> bool { + /// Returns whether we have any bitfield within the struct. + pub(crate) fn has_bitfields(&self) -> bool { match self.fields { CompFields::Error => false, CompFields::After { @@ -1189,7 +1180,7 @@ } /// Do we see a virtual function during parsing? - /// Get the has_own_virtual_method boolean. + /// Get the `has_own_virtual_method` boolean. pub(crate) fn has_own_virtual_method(&self) -> bool { self.has_own_virtual_method } @@ -1253,7 +1244,7 @@ let kind = kind?; - debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor); + debug!("CompInfo::from_ty({kind:?}, {cursor:?})"); let mut ci = CompInfo::new(kind); ci.is_forward_declaration = @@ -1424,7 +1415,7 @@ } CXCursor_TemplateTypeParameter => { let param = Item::type_param(None, cur, ctx).expect( - "Item::type_param should't fail when pointing \ + "Item::type_param shouldn't fail when pointing \ at a TemplateTypeParameter", ); ci.template_params.push(param); @@ -1441,7 +1432,7 @@ let field_name = match ci.base_members.len() { 0 => "_base".into(), - n => format!("_base_{}", n), + n => format!("_base_{n}"), }; let type_id = Item::from_ty_or_ref(cur.cur_type(), cur, None, ctx); @@ -1449,8 +1440,7 @@ ty: type_id, kind, field_name, - is_pub: cur.access_specifier() == - clang_sys::CX_CXXPublic, + is_pub: cur.access_specifier() == CX_CXXPublic, }); } CXCursor_Constructor | CXCursor_Destructor | @@ -1589,7 +1579,7 @@ _ => CompKind::Struct, }, _ => { - warn!("Unknown kind for comp type: {:?}", cursor); + warn!("Unknown kind for comp type: {cursor:?}"); return Err(ParseError::Continue); } }) @@ -1649,7 +1639,7 @@ pub(crate) fn already_packed(&self, ctx: &BindgenContext) -> Option { let mut total_size: usize = 0; - for field in self.fields().iter() { + for field in self.fields() { let layout = field.layout(ctx)?; if layout.align != 0 && total_size % layout.align != 0 { @@ -1674,7 +1664,7 @@ layout: Option<&Layout>, ) { let packed = self.is_packed(ctx, layout); - self.fields.compute_bitfield_units(ctx, packed) + self.fields.compute_bitfield_units(ctx, packed); } /// Assign for each anonymous field a generated name. @@ -1685,12 +1675,12 @@ /// Returns whether the current union can be represented as a Rust `union` /// /// Requirements: - /// 1. Current RustTarget allows for `untagged_union` - /// 2. Each field can derive `Copy` or we use ManuallyDrop. + /// 1. Current `RustTarget` allows for `untagged_union` + /// 2. Each field can derive `Copy` or we use `ManuallyDrop`. /// 3. It's not zero-sized. /// /// Second boolean returns whether all fields can be copied (and thus - /// ManuallyDrop is not needed). + /// `ManuallyDrop` is not needed). pub(crate) fn is_rust_union( &self, ctx: &BindgenContext, @@ -1728,7 +1718,7 @@ return (false, false); } - if layout.map_or(false, |l| l.size == 0) { + if layout.is_some_and(|l| l.size == 0) { return (false, false); } @@ -1792,7 +1782,11 @@ impl IsOpaque for CompInfo { type Extra = Option; - fn is_opaque(&self, ctx: &BindgenContext, layout: &Option) -> bool { + fn is_opaque( + &self, + ctx: &BindgenContext, + _layout: &Option, + ) -> bool { if self.has_non_type_template_params || self.has_unevaluable_bit_field_width { @@ -1821,23 +1815,6 @@ }), }) { return true; - } - - if !ctx.options().rust_features().repr_packed_n { - // If we don't have `#[repr(packed(N)]`, the best we can - // do is make this struct opaque. - // - // See https://github.com/rust-lang/rust-bindgen/issues/537 and - // https://github.com/rust-lang/rust/issues/33158 - if self.is_packed(ctx, layout.as_ref()) && - layout.map_or(false, |l| l.align > 1) - { - warn!("Found a type that is both packed and aligned to greater than \ - 1; Rust before version 1.33 doesn't have `#[repr(packed(N))]`, so we \ - are treating it as opaque. You may wish to set bindgen's rust target \ - version to 1.33 or later to enable `#[repr(packed(N))]` support."); - return true; - } } false diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/context.rs firefox-140.10.2/third_party/rust/bindgen/ir/context.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/context.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/context.rs Mon May 11 04:49:32 2026 @@ -29,14 +29,14 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::{BTreeSet, HashMap as StdHashMap}; -use std::iter::IntoIterator; use std::mem; +use std::path::Path; /// An identifier for some kind of IR item. #[derive(Debug, Copy, Clone, Eq, PartialOrd, Ord, Hash)] pub(crate) struct ItemId(usize); -/// Declare a newtype around `ItemId` with convesion methods. +/// Declare a newtype around `ItemId` with conversion methods. macro_rules! item_id_newtype { ( $( #[$attr:meta] )* @@ -196,8 +196,8 @@ impl ItemId { /// Get a numeric representation of this ID. - pub(crate) fn as_usize(&self) -> usize { - (*self).into() + pub(crate) fn as_usize(self) -> usize { + self.into() } } @@ -308,7 +308,7 @@ /// A context used during parsing and generation of structs. #[derive(Debug)] pub(crate) struct BindgenContext { - /// The map of all the items parsed so far, keyed off ItemId. + /// The map of all the items parsed so far, keyed off `ItemId`. items: Vec>, /// Clang USR to type map. This is needed to be able to associate types with @@ -317,7 +317,7 @@ /// Maps from a cursor to the item ID of the named template type parameter /// for that cursor. - type_params: HashMap, + type_params: HashMap, /// A cursor to module map. Similar reason than above. modules: HashMap, @@ -328,13 +328,13 @@ /// Current module being traversed. current_module: ModuleId, - /// A HashMap keyed on a type definition, and whose value is the parent ID + /// A `HashMap` keyed on a type definition, and whose value is the parent ID /// of the declaration. /// /// This is used to handle the cases where the semantic and the lexical /// parents of the cursor differ, like when a nested class is defined /// outside of the parent class. - semantic_parents: HashMap, + semantic_parents: HashMap, /// A stack with the current type declarations and types we're parsing. This /// is needed to avoid infinite recursion when parsing a type like: @@ -344,7 +344,7 @@ /// This means effectively, that a type has a potential ID before knowing if /// it's a correct type. But that's not important in practice. /// - /// We could also use the `types` HashMap, but my intention with it is that + /// We could also use the `types` `HashMap`, but my intention with it is that /// only valid types and declarations end up there, and this could /// potentially break that assumption. currently_parsed_types: Vec, @@ -353,7 +353,7 @@ /// hard errors while parsing duplicated macros, as well to allow macro /// expression parsing. /// - /// This needs to be an std::HashMap because the cexpr API requires it. + /// This needs to be an `std::HashMap` because the `cexpr` API requires it. parsed_macros: StdHashMap, cexpr::expr::EvalResult>, /// A map with all include locations. @@ -377,12 +377,18 @@ /// The translation unit for parsing. translation_unit: clang::TranslationUnit, + /// The translation unit for macro fallback parsing. + fallback_tu: Option, + /// Target information that can be useful for some stuff. target_info: clang::TargetInfo, /// The options given by the user via cli or other medium. options: BindgenOptions, + /// Whether an opaque array was generated + generated_opaque_array: RefCell>, + /// Whether a bindgen complex was generated generated_bindgen_complex: Cell, @@ -496,7 +502,7 @@ traversal: ItemTraversal<'ctx, ItemSet, Vec>, } -impl<'ctx> Iterator for AllowlistedItemsTraversal<'ctx> { +impl Iterator for AllowlistedItemsTraversal<'_> { type Item = ItemId; fn next(&mut self) -> Option { @@ -585,10 +591,12 @@ collected_typerefs: false, in_codegen: false, translation_unit, + fallback_tu: None, target_info, options, generated_bindgen_complex: Cell::new(false), generated_bindgen_float16: Cell::new(false), + generated_opaque_array: Default::default(), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, @@ -613,7 +621,7 @@ self.target_info.triple.starts_with("wasm32-") } - /// Creates a timer for the current bindgen phase. If time_phases is `true`, + /// Creates a timer for the current bindgen phase. If `time_phases` is `true`, /// the timer will print to stderr when it is dropped, otherwise it will do /// nothing. pub(crate) fn timer<'a>(&self, name: &'a str) -> Timer<'a> { @@ -692,10 +700,7 @@ declaration: Option, location: Option, ) { - debug!( - "BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", - item, declaration, location - ); + debug!("BindgenContext::add_item({item:?}, declaration: {declaration:?}, loc: {location:?}"); debug_assert!( declaration.is_some() || !item.kind().is_type() || @@ -719,7 +724,7 @@ self.need_bitfield_allocation.push(id); } - let old_item = mem::replace(&mut self.items[id.0], Some(item)); + let old_item = self.items[id.0].replace(item); assert!( old_item.is_none(), "should not have already associated an item with the given id" @@ -747,8 +752,7 @@ // Fortunately, we don't care about those types being // duplicated, so we can just ignore them. debug!( - "Invalid declaration {:?} found for type {:?}", - declaration, + "Invalid declaration {declaration:?} found for type {:?}", self.resolve_item_fallible(id) .unwrap() .kind() @@ -762,10 +766,7 @@ } else if let Some(usr) = declaration.usr() { TypeKey::Usr(usr) } else { - warn!( - "Valid declaration with no USR: {:?}, {:?}", - declaration, location - ); + warn!("Valid declaration with no USR: {declaration:?}, {location:?}"); TypeKey::Declaration(declaration) }; @@ -779,7 +780,7 @@ /// codegen'd, even if its parent is not allowlisted. See issue #769 for /// details. fn add_item_to_module(&mut self, item: &Item) { - assert!(item.id() != self.root_module); + assert_ne!(item.id(), self.root_module); assert!(self.resolve_item_fallible(item.id()).is_none()); if let Some(ref mut parent) = self.items[item.parent_id().0] { @@ -801,7 +802,7 @@ self.current_module ); - self.items[(self.current_module.0).0] + self.items[self.current_module.0 .0] .as_mut() .expect("Should always have an item for self.current_module") .as_module_mut() @@ -811,15 +812,8 @@ } /// Add a new named template type parameter to this context's item set. - pub(crate) fn add_type_param( - &mut self, - item: Item, - definition: clang::Cursor, - ) { - debug!( - "BindgenContext::add_type_param: item = {:?}; definition = {:?}", - item, definition - ); + pub(crate) fn add_type_param(&mut self, item: Item, definition: Cursor) { + debug!("BindgenContext::add_type_param: item = {item:?}; definition = {definition:?}"); assert!( item.expect_type().is_type_param(), @@ -833,7 +827,7 @@ self.add_item_to_module(&item); let id = item.id(); - let old_item = mem::replace(&mut self.items[id.0], Some(item)); + let old_item = self.items[id.0].replace(item); assert!( old_item.is_none(), "should not have already associated an item with the given id" @@ -850,15 +844,12 @@ /// Get the named type defined at the given cursor location, if we've /// already added one. - pub(crate) fn get_type_param( - &self, - definition: &clang::Cursor, - ) -> Option { + pub(crate) fn get_type_param(&self, definition: &Cursor) -> Option { assert_eq!( definition.kind(), clang_sys::CXCursor_TemplateTypeParameter ); - self.type_params.get(definition).cloned() + self.type_params.get(definition).copied() } // TODO: Move all this syntax crap to other part of the code. @@ -874,7 +865,7 @@ "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" | + "fn" | "for" | "gen" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" | "return" | "Self" | "self" | "sizeof" | "static" | @@ -927,23 +918,20 @@ /// Gather all the unresolved type references. fn collect_typerefs( &mut self, - ) -> Vec<(ItemId, clang::Type, clang::Cursor, Option)> { + ) -> Vec<(ItemId, clang::Type, Cursor, Option)> { debug_assert!(!self.collected_typerefs); self.collected_typerefs = true; let mut typerefs = vec![]; for (id, item) in self.items() { let kind = item.kind(); - let ty = match kind.as_type() { - Some(ty) => ty, - None => continue, - }; + let Some(ty) = kind.as_type() else { continue }; if let TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) = *ty.kind() { typerefs.push((id, *ty, loc, parent_id)); - }; + } } typerefs } @@ -999,7 +987,7 @@ let result = f(self, &mut item); - let existing = mem::replace(&mut self.items[id.0], Some(item)); + let existing = self.items[id.0].replace(item); assert!(existing.is_none()); result @@ -1074,9 +1062,8 @@ // Calls to `canonical_name` are expensive, so eagerly filter out // items that cannot be replaced. - let ty = match item.kind().as_type() { - Some(ty) => ty, - None => continue, + let Some(ty) = item.kind().as_type() else { + continue; }; match *ty.kind() { @@ -1105,7 +1092,7 @@ } for (id, replacement_id) in replacements { - debug!("Replacing {:?} with {:?}", id, replacement_id); + debug!("Replacing {id:?} with {replacement_id:?}"); let new_parent = { let item_id: ItemId = id.into(); let item = self.items[item_id.0].as_mut().unwrap(); @@ -1142,7 +1129,7 @@ .chain(Some(immut_self.root_module.into())) .find(|id| { let item = immut_self.resolve_item(*id); - item.as_module().map_or(false, |m| { + item.as_module().is_some_and(|m| { m.children().contains(&replacement_id.into()) }) }) @@ -1230,7 +1217,7 @@ /// When the `__testing_only_extra_assertions` feature is enabled, this /// function walks the IR graph and asserts that we do not have any edges - /// referencing an ItemId for which we do not have an associated IR item. + /// referencing an `ItemId` for which we do not have an associated IR item. fn assert_no_dangling_references(&self) { if cfg!(feature = "__testing_only_extra_assertions") { for _ in self.assert_no_dangling_item_traversal() { @@ -1241,9 +1228,9 @@ fn assert_no_dangling_item_traversal( &self, - ) -> traversal::AssertNoDanglingItemsTraversal { + ) -> traversal::AssertNoDanglingItemsTraversal<'_> { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); let roots = self.items().map(|(id, _)| id); traversal::AssertNoDanglingItemsTraversal::new( @@ -1259,7 +1246,7 @@ fn assert_every_item_in_a_module(&self) { if cfg!(feature = "__testing_only_extra_assertions") { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); for (id, _item) in self.items() { if id == self.root_module { @@ -1277,19 +1264,13 @@ id.ancestors(self) .chain(Some(self.root_module.into())) .any(|ancestor| { - debug!( - "Checking if {:?} is a child of {:?}", - id, ancestor - ); + debug!("Checking if {id:?} is a child of {ancestor:?}"); self.resolve_item(ancestor) .as_module() - .map_or(false, |m| { - m.children().contains(&id) - }) + .is_some_and(|m| m.children().contains(&id)) }) }, - "{:?} should be in some ancestor module's children set", - id + "{id:?} should be in some ancestor module's children set" ); } } @@ -1314,7 +1295,7 @@ .as_ref() .unwrap() .get(&id) - .cloned() + .copied() .unwrap_or(SizednessResult::ZeroSized) } @@ -1338,7 +1319,7 @@ .as_ref() .unwrap() .get(&id.into()) - .cloned() + .copied() .unwrap_or(HasVtableResult::No) } @@ -1418,8 +1399,7 @@ self.used_template_parameters .as_ref() .expect("should have found template parameter usage if we're in codegen") - .get(&item) - .map_or(false, |items_used_params| items_used_params.contains(&template_param)) + .get(&item).is_some_and(|items_used_params| items_used_params.contains(&template_param)) } /// Return `true` if `item` uses any unbound, generic template parameters, @@ -1438,7 +1418,7 @@ "should have template parameter usage info in codegen phase", ) .get(&item) - .map_or(false, |used| !used.is_empty()) + .is_some_and(|used| !used.is_empty()) } // This deserves a comment. Builtin types don't get a valid declaration, so @@ -1450,11 +1430,11 @@ // If at some point we care about the memory here, probably a map TypeKind // -> builtin type ItemId would be the best to improve that. fn add_builtin_item(&mut self, item: Item) { - debug!("add_builtin_item: item = {:?}", item); + debug!("add_builtin_item: item = {item:?}"); debug_assert!(item.kind().is_type()); self.add_item_to_module(&item); let id = item.id(); - let old_item = mem::replace(&mut self.items[id.0], Some(item)); + let old_item = self.items[id.0].replace(item); assert!(old_item.is_none(), "Inserted type twice?"); } @@ -1509,7 +1489,7 @@ let item_id = item_id.into(); match self.resolve_item_fallible(item_id) { Some(item) => item, - None => panic!("Not an item: {:?}", item_id), + None => panic!("Not an item: {item_id:?}"), } } @@ -1524,11 +1504,11 @@ /// correct type definition afterwards. /// /// TODO(emilio): We could consider doing this only when - /// declaration.lexical_parent() != definition.lexical_parent(), but it's + /// `declaration.lexical_parent() != definition.lexical_parent()`, but it's /// not sure it's worth it. pub(crate) fn add_semantic_parent( &mut self, - definition: clang::Cursor, + definition: Cursor, parent_id: ItemId, ) { self.semantic_parents.insert(definition, parent_id); @@ -1537,9 +1517,9 @@ /// Returns a known semantic parent for a given definition. pub(crate) fn known_semantic_parent( &self, - definition: clang::Cursor, + definition: Cursor, ) -> Option { - self.semantic_parents.get(&definition).cloned() + self.semantic_parents.get(&definition).copied() } /// Given a cursor pointing to the location of a template instantiation, @@ -1587,7 +1567,6 @@ self.currently_parsed_types() .iter() .find(|partial_ty| *partial_ty.decl() == referenced) - .cloned() }) .and_then(|template_decl| { let num_template_params = @@ -1612,7 +1591,7 @@ /// function template declarations(!?!??!). /// /// The only way to do this is manually inspecting the AST and looking for - /// TypeRefs and TemplateRefs inside. This, unfortunately, doesn't work for + /// `TypeRefs` and `TemplateRefs` inside. This, unfortunately, doesn't work for /// more complex cases, see the comment on the assertion below. /// /// To add insult to injury, the AST itself has structure that doesn't make @@ -1643,7 +1622,7 @@ with_id: ItemId, template: TypeId, ty: &clang::Type, - location: clang::Cursor, + location: Cursor, ) -> Option { let num_expected_args = self.resolve_type(template).num_self_template_params(self); @@ -1776,8 +1755,7 @@ // Bypass all the validations in add_item explicitly. debug!( "instantiate_template: inserting nested \ - instantiation item: {:?}", - sub_item + instantiation item: {sub_item:?}" ); self.add_item_to_module(&sub_item); debug_assert_eq!(sub_id, sub_item.id()); @@ -1787,8 +1765,7 @@ } _ => { warn!( - "Found template arg cursor we can't handle: {:?}", - child + "Found template arg cursor we can't handle: {child:?}" ); found_const_arg = true; } @@ -1839,7 +1816,7 @@ ); // Bypass all the validations in add_item explicitly. - debug!("instantiate_template: inserting item: {:?}", item); + debug!("instantiate_template: inserting item: {item:?}"); self.add_item_to_module(&item); debug_assert_eq!(with_id, item.id()); self.items[with_id.0] = Some(item); @@ -1859,7 +1836,7 @@ .usr() .and_then(|usr| self.types.get(&TypeKey::Usr(usr))) }) - .cloned() + .copied() } /// Looks up for an already resolved type, either because it's builtin, or @@ -1869,19 +1846,15 @@ with_id: ItemId, parent_id: Option, ty: &clang::Type, - location: Option, + location: Option, ) -> Option { use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef}; - debug!( - "builtin_or_resolved_ty: {:?}, {:?}, {:?}, {:?}", - ty, location, with_id, parent_id - ); + debug!("builtin_or_resolved_ty: {ty:?}, {location:?}, {with_id:?}, {parent_id:?}"); if let Some(decl) = ty.canonical_declaration(location.as_ref()) { if let Some(id) = self.get_resolved_type(&decl) { debug!( - "Already resolved ty {:?}, {:?}, {:?} {:?}", - id, decl, ty, location + "Already resolved ty {id:?}, {decl:?}, {ty:?} {location:?}" ); // If the declaration already exists, then either: // @@ -2006,6 +1979,9 @@ CXType_Short => TypeKind::Int(IntKind::Short), CXType_UShort => TypeKind::Int(IntKind::UShort), CXType_WChar => TypeKind::Int(IntKind::WChar), + CXType_Char16 if self.options().use_distinct_char16_t => { + TypeKind::Int(IntKind::Char16) + } CXType_Char16 => TypeKind::Int(IntKind::U16), CXType_Char32 => TypeKind::Int(IntKind::U32), CXType_Long => TypeKind::Int(IntKind::Long), @@ -2029,8 +2005,7 @@ CXType_LongDouble => FloatKind::LongDouble, CXType_Float128 => FloatKind::Float128, _ => panic!( - "Non floating-type complex? {:?}, {:?}", - ty, float_type, + "Non floating-type complex? {ty:?}, {float_type:?}", ), }; TypeKind::Complex(float_kind) @@ -2061,6 +2036,93 @@ &self.translation_unit } + /// Initialize fallback translation unit if it does not exist and + /// then return a mutable reference to the fallback translation unit. + pub(crate) fn try_ensure_fallback_translation_unit( + &mut self, + ) -> Option<&mut clang::FallbackTranslationUnit> { + if self.fallback_tu.is_none() { + let file = format!( + "{}/.macro_eval.c", + match self.options().clang_macro_fallback_build_dir { + Some(ref path) => path.as_os_str().to_str()?, + None => ".", + } + ); + + let index = clang::Index::new(false, false); + + let mut header_names_to_compile = Vec::new(); + let mut header_paths = Vec::new(); + let mut header_includes = Vec::new(); + let single_header = self.options().input_headers.last().cloned()?; + for input_header in &self.options.input_headers + [..self.options.input_headers.len() - 1] + { + let path = Path::new(input_header.as_ref()); + if let Some(header_path) = path.parent() { + if header_path == Path::new("") { + header_paths.push("."); + } else { + header_paths.push(header_path.as_os_str().to_str()?); + } + } else { + header_paths.push("."); + } + let header_name = path.file_name()?.to_str()?; + header_includes.push(header_name.to_string()); + header_names_to_compile + .push(header_name.split(".h").next()?.to_string()); + } + let pch = format!( + "{}/{}", + match self.options().clang_macro_fallback_build_dir { + Some(ref path) => path.as_os_str().to_str()?, + None => ".", + }, + header_names_to_compile.join("-") + "-precompile.h.pch" + ); + + let mut c_args = self.options.fallback_clang_args.clone(); + c_args.push("-x".to_string().into_boxed_str()); + c_args.push("c-header".to_string().into_boxed_str()); + for header_path in header_paths { + c_args.push(format!("-I{header_path}").into_boxed_str()); + } + for header_include in header_includes { + c_args.push("-include".to_string().into_boxed_str()); + c_args.push(header_include.into_boxed_str()); + } + let mut tu = clang::TranslationUnit::parse( + &index, + &single_header, + &c_args, + &[], + clang_sys::CXTranslationUnit_ForSerialization, + )?; + tu.save(&pch).ok()?; + + let mut c_args = vec![ + "-include-pch".to_string().into_boxed_str(), + pch.clone().into_boxed_str(), + ]; + let mut skip_next = false; + for arg in &self.options.fallback_clang_args { + if arg.as_ref() == "-include" { + skip_next = true; + } else if skip_next { + skip_next = false; + } else { + c_args.push(arg.clone()); + } + } + self.fallback_tu = + Some(clang::FallbackTranslationUnit::new(file, pch, &c_args)?); + } + + self.fallback_tu.as_mut() + } + /// Have we parsed the macro named `macro_name` already? pub(crate) fn parsed_macro(&self, macro_name: &[u8]) -> bool { self.parsed_macros.contains_key(macro_name) @@ -2096,19 +2158,14 @@ pub(crate) fn replace(&mut self, name: &[String], potential_ty: ItemId) { match self.replacements.entry(name.into()) { Entry::Vacant(entry) => { - debug!( - "Defining replacement for {:?} as {:?}", - name, potential_ty - ); + debug!("Defining replacement for {name:?} as {potential_ty:?}"); entry.insert(potential_ty); } Entry::Occupied(occupied) => { warn!( - "Replacement for {:?} already defined as {:?}; \ - ignoring duplicate replacement definition as {:?}", - name, + "Replacement for {name:?} already defined as {:?}; \ + ignoring duplicate replacement definition as {potential_ty:?}", occupied.get(), - potential_ty ); } } @@ -2143,7 +2200,7 @@ /// namespace. fn tokenize_namespace( &self, - cursor: &clang::Cursor, + cursor: &Cursor, ) -> (Option, ModuleKind) { assert_eq!( cursor.kind(), @@ -2154,7 +2211,7 @@ let mut module_name = None; let spelling = cursor.spelling(); if !spelling.is_empty() { - module_name = Some(spelling) + module_name = Some(spelling); } let mut kind = ModuleKind::Normal; @@ -2194,33 +2251,31 @@ ); } 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 - ); } + // This is _likely_, but not certainly, a macro that's + // been placed just before the namespace keyword. + // Unfortunately, clang tokens don't let us easily see + // through the ifdef tokens, so we don't know what this + // token should really be. Instead of panicking though, + // we warn the user that we assumed the token was blank, + // and then move on. + // + // See also https://github.com/rust-lang/rust-bindgen/issues/1676. + warn!("Ignored unknown namespace prefix '{}' at {token:?} in {cursor:?}", String::from_utf8_lossy(name)); } } } + if cursor.is_inline_namespace() { + kind = ModuleKind::Inline; + } + (module_name, kind) } - /// Given a CXCursor_Namespace cursor, return the item ID of the + /// Given a `CXCursor_Namespace` cursor, return the item ID of the /// corresponding module, or create one on the fly. - pub(crate) fn module(&mut self, cursor: clang::Cursor) -> ModuleId { + pub(crate) fn module(&mut self, cursor: Cursor) -> ModuleId { use clang_sys::*; assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person"); let cursor = cursor.canonical(); @@ -2271,7 +2326,7 @@ /// allowlisted. pub(crate) fn allowlisted_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); self.allowlisted.as_ref().unwrap() } @@ -2284,7 +2339,7 @@ derive_trait: DeriveTrait, ) -> CanDerive { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); *self .blocklisted_types_implement_traits @@ -2332,14 +2387,14 @@ /// Get a reference to the set of items we should generate. pub(crate) fn codegen_items(&self) -> &ItemSet { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); self.codegen_items.as_ref().unwrap() } /// Compute the allowlisted items set and populate `self.allowlisted`. fn compute_allowlisted_and_codegen_items(&mut self) { assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); + assert_eq!(self.current_module, self.root_module); assert!(self.allowlisted.is_none()); let _t = self.timer("compute_allowlisted_and_codegen_items"); @@ -2384,7 +2439,7 @@ } let name = item.path_for_allowlisting(self)[1..].join("::"); - debug!("allowlisted_items: testing {:?}", name); + debug!("allowlisted_items: testing {name:?}"); if self.options().allowlisted_items.matches(&name) { return true; @@ -2438,9 +2493,8 @@ return false; } - let enum_ = match *ty.kind() { - TypeKind::Enum(ref e) => e, - _ => return false, + let TypeKind::Enum(ref enum_) = *ty.kind() else { + return false; }; if ty.name().is_some() { @@ -2455,7 +2509,11 @@ ); let name = prefix_path[1..].join("::"); prefix_path.pop().unwrap(); - self.options().allowlisted_vars.matches(name) + self.options().allowlisted_vars.matches(&name) + || self + .options() + .allowlisted_items + .matches(name) }) } } @@ -2529,9 +2587,26 @@ } } + /// Call if an opaque array is generated + pub(crate) fn generated_opaque_array(&self, align: usize) { + self.generated_opaque_array.borrow_mut().insert(align); + } + + /// Whether we need to generate the opaque array type + pub(crate) fn opaque_array_types_needed(&self) -> Vec { + let mut alignments = self + .generated_opaque_array + .borrow() + .iter() + .copied() + .collect::>(); + alignments.sort_unstable(); + alignments + } + /// Call if a bindgen complex is generated pub(crate) fn generated_bindgen_complex(&self) { - self.generated_bindgen_complex.set(true) + self.generated_bindgen_complex.set(true); } /// Whether we need to generate the bindgen complex type @@ -2541,7 +2616,7 @@ /// Call if a bindgen float16 is generated pub(crate) fn generated_bindgen_float16(&self) { - self.generated_bindgen_float16.set(true) + self.generated_bindgen_float16.set(true); } /// Whether we need to generate the bindgen float16 type @@ -2714,7 +2789,7 @@ !self.cannot_derive_hash.as_ref().unwrap().contains(&id) } - /// Compute whether we can derive PartialOrd, PartialEq or Eq. + /// Compute whether we can derive `PartialOrd`, `PartialEq` or `Eq`. fn compute_cannot_derive_partialord_partialeq_or_eq(&mut self) { let _t = self.timer("compute_cannot_derive_partialord_partialeq_or_eq"); assert!(self.cannot_derive_partialeq_or_partialord.is_none()); @@ -2749,7 +2824,7 @@ .as_ref() .unwrap() .get(&id) - .cloned() + .copied() .unwrap_or(CanDerive::Yes) } @@ -3007,7 +3082,7 @@ num_params += 1; } _ => {} - }; + } clang_sys::CXChildVisit_Continue }); num_params @@ -3018,7 +3093,7 @@ } fn unused_regex_diagnostic(item: &str, name: &str, _ctx: &BindgenContext) { - warn!("unused option: {} {}", name, item); + warn!("unused option: {name} {item}"); #[cfg(feature = "experimental")] if _ctx.options().emit_diagnostics { @@ -3026,11 +3101,11 @@ Diagnostic::default() .with_title( - format!("Unused regular expression: `{}`.", item), - Level::Warn, + format!("Unused regular expression: `{item}`."), + Level::Warning, ) .add_annotation( - format!("This regular expression was passed to `{}`.", name), + format!("This regular expression was passed to `{name}`."), Level::Note, ) .display(); diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/derive.rs firefox-140.10.2/third_party/rust/bindgen/ir/derive.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/derive.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/derive.rs Mon May 11 04:49:32 2026 @@ -3,10 +3,10 @@ //! These traits tend to come in pairs: //! //! 1. A "trivial" version, whose implementations aren't allowed to recursively -//! look at other types or the results of fix point analyses. +//! look at other types or the results of fix point analyses. //! //! 2. A "normal" version, whose implementations simply query the results of a -//! fix point analysis. +//! fix point analysis. //! //! The former is used by the analyses when creating the results queried by the //! second. @@ -92,9 +92,10 @@ /// /// Initially we assume that we can derive trait for all types and then /// update our understanding as we learn more about each type. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum CanDerive { /// Yes, we can derive automatically. + #[default] Yes, /// The only thing that stops us from automatically deriving is that @@ -107,12 +108,6 @@ No, } -impl Default for CanDerive { - fn default() -> CanDerive { - CanDerive::Yes - } -} - impl CanDerive { /// Take the least upper bound of `self` and `rhs`. pub(crate) fn join(self, rhs: Self) -> Self { @@ -130,6 +125,6 @@ impl ops::BitOrAssign for CanDerive { fn bitor_assign(&mut self, rhs: Self) { - *self = self.join(rhs) + *self = self.join(rhs); } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/dot.rs firefox-140.10.2/third_party/rust/bindgen/ir/dot.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/dot.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/dot.rs Mon May 11 04:49:32 2026 @@ -17,7 +17,7 @@ out: &mut W, ) -> io::Result<()> where - W: io::Write; + W: Write; } /// Write a graphviz dot file containing our IR. @@ -41,7 +41,7 @@ if is_allowlisted { "black" } else { "gray" } )?; item.dot_attributes(ctx, &mut dot_file)?; - writeln!(&mut dot_file, r#" >];"#)?; + writeln!(&mut dot_file, " >];")?; item.trace( ctx, @@ -52,10 +52,9 @@ match writeln!( &mut dot_file, - "{} -> {} [label={:?}, color={}];", + "{} -> {} [label={edge_kind:?}, color={}];", id.as_usize(), sub_id.as_usize(), - edge_kind, if is_allowlisted { "black" } else { "gray" } ) { Ok(_) => {} diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/enum_ty.rs firefox-140.10.2/third_party/rust/bindgen/ir/enum_ty.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/enum_ty.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/enum_ty.rs Mon May 11 04:49:32 2026 @@ -59,7 +59,7 @@ ctx: &mut BindgenContext, ) -> Result { use clang_sys::*; - debug!("Enum::from_ty {:?}", ty); + debug!("Enum::from_ty {ty:?}"); if ty.kind() != CXType_Enum { return Err(ParseError::Continue); @@ -73,13 +73,13 @@ let variant_ty = repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)); - let is_bool = variant_ty.map_or(false, Type::is_bool); + let is_bool = variant_ty.is_some_and(Type::is_bool); // Assume signedness since the default type by the C standard is an int. let is_signed = variant_ty.map_or(true, |ty| match *ty.kind() { TypeKind::Int(ref int_kind) => int_kind.is_signed(), ref other => { - panic!("Since when enums can be non-integers? {:?}", other) + panic!("Since when enums can be non-integers? {other:?}") } }); @@ -310,14 +310,12 @@ /// Returns whether this variant should be enforced to be a constant by code /// generation. pub(crate) fn force_constification(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) + self.custom_behavior == Some(EnumVariantCustomBehavior::Constify) } /// Returns whether the current variant should be hidden completely from the /// resulting rust enum. pub(crate) fn hidden(&self) -> bool { - self.custom_behavior - .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) + self.custom_behavior == Some(EnumVariantCustomBehavior::Hide) } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/function.rs firefox-140.10.2/third_party/rust/bindgen/ir/function.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/function.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/function.rs Mon May 11 04:49:32 2026 @@ -9,7 +9,7 @@ use crate::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, ABIKind, Attribute}; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; -use clang_sys::{self, CXCallingConv}; +use clang_sys::CXCallingConv; use quote::TokenStreamExt; use std::io; @@ -17,7 +17,7 @@ const RUST_DERIVE_FUNPTR_LIMIT: usize = 12; -/// What kind of a function are we looking at? +/// What kind of function are we looking at? #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FunctionKind { /// A plain, free function. @@ -82,7 +82,7 @@ /// The mangled name, that is, the symbol. mangled_name: Option, - /// The link name. If specified, overwrite mangled_name. + /// The link name. If specified, overwrite `mangled_name`. link_name: Option, /// The ID pointing to the current function signature. @@ -158,11 +158,7 @@ if let Some(ref mangled) = self.mangled_name { let mangled: String = mangled.chars().flat_map(|c| c.escape_default()).collect(); - writeln!( - out, - "mangled name{}", - mangled - )?; + writeln!(out, "mangled name{mangled}")?; } Ok(()) @@ -209,7 +205,7 @@ "win64" => Ok(Self::Win64), "C-unwind" => Ok(Self::CUnwind), "system" => Ok(Self::System), - _ => Err(format!("Invalid or unknown ABI {:?}", s)), + _ => Err(format!("Invalid or unknown ABI {s:?}")), } } } @@ -251,8 +247,8 @@ impl ClangAbi { /// Returns whether this Abi is known or not. - fn is_unknown(&self) -> bool { - matches!(*self, ClangAbi::Unknown(..)) + fn is_unknown(self) -> bool { + matches!(self, ClangAbi::Unknown(..)) } } @@ -261,8 +257,7 @@ match *self { Self::Known(abi) => abi.to_tokens(tokens), Self::Unknown(cc) => panic!( - "Cannot turn unknown calling convention to tokens: {:?}", - cc + "Cannot turn unknown calling convention to tokens: {cc:?}" ), } } @@ -295,15 +290,15 @@ fn get_abi(cc: CXCallingConv) -> ClangAbi { use clang_sys::*; match cc { - CXCallingConv_Default => ClangAbi::Known(Abi::C), - CXCallingConv_C => ClangAbi::Known(Abi::C), + CXCallingConv_Default | 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_X86VectorCall | CXCallingConv_AArch64VectorCall => { + ClangAbi::Known(Abi::Vectorcall) + } CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs), CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64), - CXCallingConv_AArch64VectorCall => ClangAbi::Known(Abi::Vectorcall), other => ClangAbi::Unknown(other), } } @@ -423,7 +418,7 @@ ctx: &mut BindgenContext, ) -> Result { use clang_sys::*; - debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor); + debug!("FunctionSig::from_ty {ty:?} {cursor:?}"); // Skip function templates let kind = cursor.kind(); @@ -438,7 +433,7 @@ spelling.starts_with("operator") && !clang::is_valid_identifier(spelling) }; - if is_operator(&spelling) { + if is_operator(&spelling) && !ctx.options().represent_cxx_operators { return Err(ParseError::Continue); } @@ -538,7 +533,10 @@ let is_const = is_method && cursor.method_is_const(); let is_virtual = is_method && cursor.method_is_virtual(); let is_static = is_method && cursor.method_is_static(); - if !is_static && !is_virtual { + if !is_static && + (!is_virtual || + ctx.options().use_specific_virtual_function_receiver) + { let parent = cursor.semantic_parent(); let class = Item::parse(parent, None, ctx) .expect("Expected to parse the class"); @@ -601,7 +599,7 @@ let abi = get_abi(call_conv); if abi.is_unknown() { - warn!("Unknown calling convention: {:?}", call_conv); + warn!("Unknown calling convention: {call_conv:?}"); } Ok(Self { @@ -726,18 +724,18 @@ ) -> Result, ParseError> { use clang_sys::*; - let kind = match FunctionKind::from_cursor(&cursor) { - None => return Err(ParseError::Continue), - Some(k) => k, + let Some(kind) = FunctionKind::from_cursor(&cursor) else { + return Err(ParseError::Continue); }; - debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); + debug!("Function::parse({cursor:?}, {:?})", cursor.cur_type()); let visibility = cursor.visibility(); if visibility != CXVisibility_Default { return Err(ParseError::Continue); } - - if cursor.access_specifier() == CX_CXXPrivate { + if cursor.access_specifier() == CX_CXXPrivate && + !context.options().generate_private_functions + { return Err(ParseError::Continue); } @@ -749,9 +747,7 @@ }; if cursor.is_inlined_function() || - cursor - .definition() - .map_or(false, |x| x.is_inlined_function()) + cursor.definition().is_some_and(|x| x.is_inlined_function()) { if !context.options().generate_inline_functions && !context.options().wrap_static_fns @@ -759,7 +755,9 @@ return Err(ParseError::Continue); } - if cursor.is_deleted_function() { + if cursor.is_deleted_function() && + !context.options().generate_deleted_functions + { return Err(ParseError::Continue); } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/int.rs firefox-140.10.2/third_party/rust/bindgen/ir/int.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/int.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/int.rs Mon May 11 04:49:32 2026 @@ -54,9 +54,12 @@ /// A 16-bit signed integer. I16, - /// Either a `char16_t` or a `wchar_t`. + /// A 16-bit integer, used only for enum size representation. U16, + /// The C++ type `char16_t`, which is its own type (unlike in C). + Char16, + /// A 32-bit signed integer. I32, @@ -94,14 +97,12 @@ // to know whether it is or not right now (unlike char, there's no // WChar_S / WChar_U). Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 | - WChar | U32 | U64 | U128 => false, + Char16 | WChar | U32 | U64 | U128 => false, SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 | I128 => true, - Char { is_signed } => is_signed, - - Custom { is_signed, .. } => is_signed, + Char { is_signed } | Custom { is_signed, .. } => is_signed, } } @@ -112,7 +113,7 @@ use self::IntKind::*; Some(match *self { Bool | UChar | SChar | U8 | I8 | Char { .. } => 1, - U16 | I16 => 2, + U16 | I16 | Char16 => 2, U32 | I32 => 4, U64 | I64 => 8, I128 | U128 => 16, diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/item.rs firefox-140.10.2/third_party/rust/bindgen/ir/item.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/item.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/item.rs Mon May 11 04:49:32 2026 @@ -12,21 +12,20 @@ use super::dot::DotAttributes; use super::function::{Function, FunctionKind}; use super::item_kind::ItemKind; -use super::layout::Opaque; use super::module::Module; use super::template::{AsTemplateParam, TemplateParameters}; use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::{Type, TypeKind}; +use crate::callbacks::ItemInfo; use crate::clang; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; -use lazycell::LazyCell; - -use std::cell::Cell; +use std::cell::{Cell, OnceCell}; use std::collections::BTreeSet; use std::fmt::Write; use std::io; use std::iter; +use std::sync::OnceLock; /// A trait to get the canonical name from an item. /// @@ -45,7 +44,7 @@ /// The same, but specifies the path that needs to be followed to reach an item. /// -/// To contrast with canonical_name, here's an example: +/// To contrast with `canonical_name`, here's an example: /// /// ```c++ /// namespace foo { @@ -85,13 +84,6 @@ fn has_type_param_in_array(&self, ctx: &BindgenContext) -> bool; } -#[allow(dead_code)] -/// A trait for determining if some IR thing has float or not. -pub(crate) trait HasFloat { - /// Returns `true` if the thing has float, and `false` otherwise. - fn has_float(&self, ctx: &BindgenContext) -> bool; -} - /// A trait for iterating over an item and its parents and up its ancestor chain /// up to (but not including) the implicit root module. pub(crate) trait ItemAncestors { @@ -111,6 +103,7 @@ DebugOnlyItemSet } + #[allow(clippy::trivially_copy_pass_by_ref)] fn contains(&self, _id: &ItemId) -> bool { false } @@ -135,7 +128,7 @@ } } -impl<'a> Iterator for ItemAncestorsIter<'a> { +impl Iterator for ItemAncestorsIter<'_> { type Item = ItemId; fn next(&mut self) -> Option { @@ -383,11 +376,11 @@ /// The item's local ID, unique only amongst its siblings. Only used for /// anonymous items. /// - /// Lazily initialized in local_id(). + /// Lazily initialized in `local_id()`. /// /// Note that only structs, unions, and enums get a local type ID. In any /// case this is an implementation detail. - local_id: LazyCell, + local_id: OnceCell, /// The next local ID to use for a child or template instantiation. next_child_local_id: Cell, @@ -396,11 +389,11 @@ /// /// This is a fairly used operation during codegen so this makes bindgen /// considerably faster in those cases. - canonical_name: LazyCell, + canonical_name: OnceCell, /// The path to use for allowlisting and other name-based checks, as /// returned by `path_for_allowlisting`, lazily constructed. - path_for_allowlisting: LazyCell>, + path_for_allowlisting: OnceCell>, /// A doc comment over the item, if any. comment: Option, @@ -438,10 +431,10 @@ debug_assert!(id != parent_id || kind.is_module()); Item { id, - local_id: LazyCell::new(), + local_id: OnceCell::new(), next_child_local_id: Cell::new(1), - canonical_name: LazyCell::new(), - path_for_allowlisting: LazyCell::new(), + canonical_name: OnceCell::new(), + path_for_allowlisting: OnceCell::new(), parent_id, comment, annotations: annotations.unwrap_or_default(), @@ -457,7 +450,7 @@ ctx: &mut BindgenContext, ) -> TypeId { let location = ty.declaration().location(); - let ty = Opaque::from_clang_ty(ty, ctx); + let ty = Type::new_opaque_from_clang_ty(ty, ctx); let kind = ItemKind::Type(ty); let parent = ctx.root_module().into(); ctx.add_item( @@ -500,7 +493,7 @@ self.ancestors(ctx) .filter(|id| { - ctx.resolve_item(*id).as_module().map_or(false, |module| { + ctx.resolve_item(*id).as_module().is_some_and(|module| { !module.is_inline() || ctx.options().conservative_inline_namespaces }) @@ -542,7 +535,7 @@ /// below this item's lexical scope, meaning that this can be useful for /// generating relatively stable identifiers within a scope. pub(crate) fn local_id(&self, ctx: &BindgenContext) -> usize { - *self.local_id.borrow_with(|| { + *self.local_id.get_or_init(|| { let parent = ctx.resolve_item(self.parent_id); parent.next_child_local_id() }) @@ -590,9 +583,8 @@ let mut parent = self.parent_id; loop { - let parent_item = match ctx.resolve_item_fallible(parent) { - Some(item) => item, - None => return false, + let Some(parent_item) = ctx.resolve_item_fallible(parent) else { + return false; }; if parent_item.id() == ctx.root_module() { @@ -677,7 +669,7 @@ } } - /// Take out item NameOptions + /// Take out item `NameOptions` pub(crate) fn name<'a>( &'a self, ctx: &'a BindgenContext, @@ -725,7 +717,7 @@ s } - /// Helper function for full_disambiguated_name + /// Helper function for `full_disambiguated_name` fn push_disambiguated_name( &self, ctx: &BindgenContext, @@ -735,7 +727,7 @@ to.push_str(&self.canonical_name(ctx)); if let ItemKind::Type(ref ty) = *self.kind() { if let TypeKind::TemplateInstantiation(ref inst) = *ty.kind() { - to.push_str(&format!("_open{}_", level)); + let _ = write!(to, "_open{level}_"); for arg in inst.template_arguments() { arg.into_resolver() .through_type_refs() @@ -743,7 +735,7 @@ .push_disambiguated_name(ctx, to, level + 1); to.push('_'); } - to.push_str(&format!("close{}", level)); + let _ = write!(to, "close{level}"); } } } @@ -794,22 +786,20 @@ match *self.kind() { ItemKind::Var(ref var) => var.name().to_owned(), - ItemKind::Module(ref module) => { - module.name().map(ToOwned::to_owned).unwrap_or_else(|| { - format!("_bindgen_mod_{}", self.exposed_id(ctx)) - }) - } - ItemKind::Type(ref ty) => { - ty.sanitized_name(ctx).map(Into::into).unwrap_or_else(|| { - format!("_bindgen_ty_{}", self.exposed_id(ctx)) - }) - } + ItemKind::Module(ref module) => module.name().map_or_else( + || format!("_bindgen_mod_{}", self.exposed_id(ctx)), + ToOwned::to_owned, + ), + ItemKind::Type(ref ty) => ty.sanitized_name(ctx).map_or_else( + || format!("_bindgen_ty_{}", self.exposed_id(ctx)), + Into::into, + ), ItemKind::Function(ref fun) => { let mut name = fun.name().to_owned(); if let Some(idx) = self.overload_index(ctx) { if idx > 0 { - write!(&mut name, "{}", idx).unwrap(); + write!(&mut name, "{idx}").unwrap(); } } @@ -932,8 +922,19 @@ let name = names.join("_"); let name = if opt.user_mangled == UserMangled::Yes { + let item_info = ItemInfo { + name: &name, + kind: match self.kind() { + ItemKind::Module(..) => crate::callbacks::ItemKind::Module, + ItemKind::Type(..) => crate::callbacks::ItemKind::Type, + ItemKind::Function(..) => { + crate::callbacks::ItemKind::Function + } + ItemKind::Var(..) => crate::callbacks::ItemKind::Var, + }, + }; ctx.options() - .last_callback(|callbacks| callbacks.item_name(&name)) + .last_callback(|callbacks| callbacks.item_name(item_info)) .unwrap_or(name) } else { name @@ -948,13 +949,13 @@ // Only use local ids for enums, classes, structs and union types. All // other items use their global ID. let ty_kind = self.kind().as_type().map(|t| t.kind()); - if let Some(ty_kind) = ty_kind { - match *ty_kind { - TypeKind::Comp(..) | - TypeKind::TemplateInstantiation(..) | - TypeKind::Enum(..) => return self.local_id(ctx).to_string(), - _ => {} - } + if let Some( + TypeKind::Comp(..) | + TypeKind::TemplateInstantiation(..) | + TypeKind::Enum(..), + ) = ty_kind + { + return self.local_id(ctx).to_string(); } // Note that this `id_` prefix prevents (really unlikely) collisions @@ -986,9 +987,8 @@ // Do not jump through aliases, except for aliases that point to a type // with the same name, since we dont generate coe for them. let item = self.id.into_resolver().through_type_refs().resolve(ctx); - let type_ = match *item.kind() { - ItemKind::Type(ref type_) => type_, - _ => return false, + let ItemKind::Type(ref type_) = *item.kind() else { + return false; }; match *type_.kind() { @@ -1024,15 +1024,15 @@ FunctionKind::Method(MethodKind::Constructor) => { cc.constructors() } - FunctionKind::Method(MethodKind::Destructor) | - FunctionKind::Method(MethodKind::VirtualDestructor { - .. - }) => cc.destructors(), - FunctionKind::Method(MethodKind::Static) | - FunctionKind::Method(MethodKind::Normal) | - FunctionKind::Method(MethodKind::Virtual { .. }) => { - cc.methods() - } + FunctionKind::Method( + MethodKind::Destructor | + MethodKind::VirtualDestructor { .. }, + ) => cc.destructors(), + FunctionKind::Method( + MethodKind::Static | + MethodKind::Normal | + MethodKind::Virtual { .. }, + ) => cc.methods(), }, } } @@ -1044,7 +1044,7 @@ ctx: &BindgenContext, ) -> &Vec { self.path_for_allowlisting - .borrow_with(|| self.compute_path(ctx, UserMangled::No)) + .get_or_init(|| self.compute_path(ctx, UserMangled::No)) } fn compute_path( @@ -1066,7 +1066,7 @@ .map(|id| ctx.resolve_item(id)) .filter(|item| { item.id() == target.id() || - item.as_module().map_or(false, |module| { + item.as_module().is_some_and(|module| { !module.is_inline() || ctx.options().conservative_inline_namespaces }) @@ -1085,9 +1085,8 @@ /// Returns a prefix for the canonical name when C naming is enabled. fn c_naming_prefix(&self) -> Option<&str> { - let ty = match self.kind { - ItemKind::Type(ref ty) => ty, - _ => return None, + let ItemKind::Type(ref ty) = self.kind else { + return None; }; Some(match ty.kind() { @@ -1130,7 +1129,7 @@ "You're not supposed to call this yet" ); self.annotations.opaque() || - self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) || + self.as_type().is_some_and(|ty| ty.is_opaque(ctx, self)) || ctx.opaque_by_name(self.path_for_allowlisting(ctx)) } } @@ -1141,14 +1140,14 @@ { fn has_vtable(&self, ctx: &BindgenContext) -> bool { let id: ItemId = (*self).into(); - id.as_type_id(ctx).map_or(false, |id| { + id.as_type_id(ctx).is_some_and(|id| { !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No) }) } fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool { let id: ItemId = (*self).into(); - id.as_type_id(ctx).map_or(false, |id| { + id.as_type_id(ctx).is_some_and(|id| { matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable) }) } @@ -1204,29 +1203,6 @@ } } -impl HasFloat for T -where - T: Copy + Into, -{ - fn has_float(&self, ctx: &BindgenContext) -> bool { - debug_assert!( - ctx.in_codegen_phase(), - "You're not supposed to call this yet" - ); - ctx.lookup_has_float(*self) - } -} - -impl HasFloat for Item { - fn has_float(&self, ctx: &BindgenContext) -> bool { - debug_assert!( - ctx.in_codegen_phase(), - "You're not supposed to call this yet" - ); - ctx.lookup_has_float(self.id()) - } -} - /// A set of items. pub(crate) type ItemSet = BTreeSet; @@ -1451,11 +1427,7 @@ CXCursor_UsingDirective | CXCursor_StaticAssert | CXCursor_FunctionTemplate => { - debug!( - "Unhandled cursor kind {:?}: {:?}", - cursor.kind(), - cursor - ); + debug!("Unhandled cursor kind {:?}: {cursor:?}", cursor.kind()); Err(ParseError::Continue) } @@ -1463,7 +1435,7 @@ let file = cursor.get_included_file_name(); match file { None => { - warn!("Inclusion of a nameless file in {:?}", cursor); + warn!("Inclusion of a nameless file in {cursor:?}"); } Some(included_file) => { for cb in &ctx.options().parse_callbacks { @@ -1481,9 +1453,8 @@ let spelling = cursor.spelling(); if !spelling.starts_with("operator") { warn!( - "Unhandled cursor kind {:?}: {:?}", + "Unhandled cursor kind {:?}: {cursor:?}", cursor.kind(), - cursor ); } Err(ParseError::Continue) @@ -1520,10 +1491,7 @@ parent_id: Option, ctx: &mut BindgenContext, ) -> TypeId { - debug!( - "from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}", - potential_id, ty, location, parent_id - ); + debug!("from_ty_or_ref_with_id: {potential_id:?} {ty:?}, {location:?}, {parent_id:?}"); if ctx.collected_typerefs() { debug!("refs already collected, resolving directly"); @@ -1543,11 +1511,11 @@ &ty, Some(location), ) { - debug!("{:?} already resolved: {:?}", ty, location); + debug!("{ty:?} already resolved: {location:?}"); return ty; } - debug!("New unresolved type reference: {:?}, {:?}", ty, location); + debug!("New unresolved type reference: {ty:?}, {location:?}"); let is_const = ty.is_const(); let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id); @@ -1597,14 +1565,13 @@ use clang_sys::*; debug!( - "Item::from_ty_with_id: {:?}\n\ - \tty = {:?},\n\ - \tlocation = {:?}", - id, ty, location + "Item::from_ty_with_id: {id:?}\n\ + \tty = {ty:?},\n\ + \tlocation = {location:?}", ); - if ty.kind() == clang_sys::CXType_Unexposed || - location.cur_type().kind() == clang_sys::CXType_Unexposed + if ty.kind() == CXType_Unexposed || + location.cur_type().kind() == CXType_Unexposed { if ty.is_associated_type() || location.cur_type().is_associated_type() @@ -1624,7 +1591,7 @@ // ignore function bodies. See issue #2036.) if let Some(ref parent) = ty.declaration().fallible_semantic_parent() { if FunctionKind::from_cursor(parent).is_some() { - debug!("Skipping type declared inside function: {:?}", ty); + debug!("Skipping type declared inside function: {ty:?}"); return Ok(Item::new_opaque_type(id, ty, ctx)); } } @@ -1634,10 +1601,7 @@ canonical_def.unwrap_or_else(|| ty.declaration()) }; - let comment = location - .raw_comment() - .or_else(|| decl.raw_comment()) - .or_else(|| location.raw_comment()); + let comment = location.raw_comment().or_else(|| decl.raw_comment()); let annotations = Annotations::new(&decl).or_else(|| Annotations::new(&location)); @@ -1671,7 +1635,7 @@ .iter() .find(|ty| *ty.decl() == declaration_to_look_for) { - debug!("Avoiding recursion parsing type: {:?}", ty); + debug!("Avoiding recursion parsing type: {ty:?}"); // Unchecked because we haven't finished this type yet. return Ok(partial.id().as_type_id_unchecked()); } @@ -1742,8 +1706,7 @@ ty.spelling() ); Item::type_param(Some(id), location, ctx) - .map(Ok) - .unwrap_or(Err(ParseError::Recurse)) + .ok_or(ParseError::Recurse) } else { result } @@ -1837,10 +1800,10 @@ refd: &clang::Cursor, spelling: &str, ) -> bool { - lazy_static! { - static ref ANON_TYPE_PARAM_RE: regex::Regex = - regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap(); - } + static ANON_TYPE_PARAM_RE: OnceLock = OnceLock::new(); + let anon_type_param_re = ANON_TYPE_PARAM_RE.get_or_init(|| { + regex::Regex::new(r"^type\-parameter\-\d+\-\d+$").unwrap() + }); if refd.kind() != clang_sys::CXCursor_TemplateTypeParameter { return false; @@ -1849,7 +1812,7 @@ let refd_spelling = refd.spelling(); refd_spelling == spelling || // Allow for anonymous template parameters. - (refd_spelling.is_empty() && ANON_TYPE_PARAM_RE.is_match(spelling.as_ref())) + (refd_spelling.is_empty() && anon_type_param_re.is_match(spelling.as_ref())) } let definition = if is_template_with_spelling(&location, &ty_spelling) { @@ -1902,16 +1865,11 @@ let parent = ctx.root_module().into(); if let Some(id) = ctx.get_type_param(&definition) { - if let Some(with_id) = with_id { - return Some(ctx.build_ty_wrapper( - with_id, - id, - Some(parent), - &ty, - )); + return Some(if let Some(with_id) = with_id { + ctx.build_ty_wrapper(with_id, id, Some(parent), &ty) } else { - return Some(id); - } + id + }); } // See tests/headers/const_tparam.hpp and @@ -1939,7 +1897,7 @@ "You're not supposed to call this yet" ); self.canonical_name - .borrow_with(|| { + .get_or_init(|| { let in_namespace = ctx.options().enable_cxx_namespaces || ctx.options().disable_name_namespacing; diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/item_kind.rs firefox-140.10.2/third_party/rust/bindgen/ir/item_kind.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/item_kind.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/item_kind.rs Mon May 11 04:49:32 2026 @@ -26,7 +26,7 @@ } impl ItemKind { - /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it + /// Get a reference to this `ItemKind`'s underlying `Module`, or `None` if it /// is some other kind. pub(crate) fn as_module(&self) -> Option<&Module> { match *self { @@ -50,7 +50,7 @@ self.as_module().is_some() } - /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if + /// Get a reference to this `ItemKind`'s underlying `Function`, or `None` if /// it is some other kind. pub(crate) fn as_function(&self) -> Option<&Function> { match *self { @@ -64,13 +64,13 @@ self.as_function().is_some() } - /// Get a reference to this `ItemKind`'s underying `Function`, or panic if + /// Get a reference to this `ItemKind`'s underlying `Function`, or panic if /// it is some other kind. pub(crate) fn expect_function(&self) -> &Function { self.as_function().expect("Not a function") } - /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if + /// Get a reference to this `ItemKind`'s underlying `Type`, or `None` if /// it is some other kind. pub(crate) fn as_type(&self) -> Option<&Type> { match *self { @@ -79,7 +79,7 @@ } } - /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` + /// Get a mutable reference to this `ItemKind`'s underlying `Type`, or `None` /// if it is some other kind. pub(crate) fn as_type_mut(&mut self) -> Option<&mut Type> { match *self { @@ -93,13 +93,13 @@ self.as_type().is_some() } - /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is + /// Get a reference to this `ItemKind`'s underlying `Type`, or panic if it is /// some other kind. pub(crate) fn expect_type(&self) -> &Type { self.as_type().expect("Not a type") } - /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is + /// Get a reference to this `ItemKind`'s underlying `Var`, or `None` if it is /// some other kind. pub(crate) fn as_var(&self) -> Option<&Var> { match *self { diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/layout.rs firefox-140.10.2/third_party/rust/bindgen/ir/layout.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/layout.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/layout.rs Mon May 11 04:49:32 2026 @@ -1,10 +1,6 @@ //! Intermediate representation for the physical layout of some type. -use super::derive::CanDerive; -use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; -use crate::clang; use crate::ir::context::BindgenContext; -use std::cmp; /// A type that represents the struct layout of a type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -19,9 +15,8 @@ #[test] fn test_layout_for_size() { - use std::mem; - - let ptr_size = mem::size_of::<*mut ()>(); + use std::mem::size_of; + let ptr_size = size_of::<*mut ()>(); assert_eq!( Layout::for_size_internal(ptr_size, ptr_size), Layout::new(ptr_size, ptr_size) @@ -34,14 +29,9 @@ impl Layout { /// Gets the integer type name for a given known size. - pub(crate) fn known_type_for_size( - ctx: &BindgenContext, - size: usize, - ) -> Option { + pub(crate) fn known_type_for_size(size: usize) -> Option { Some(match size { - 16 if ctx.options().rust_features.i128_and_u128 => { - syn::parse_quote! { u128 } - } + 16 => syn::parse_quote! { u128 }, 8 => syn::parse_quote! { u64 }, 4 => syn::parse_quote! { u32 }, 2 => syn::parse_quote! { u16 }, @@ -76,63 +66,5 @@ /// alignment possible. pub(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self { Self::for_size_internal(ctx.target_pointer_size(), size) - } - - /// Get this layout as an opaque type. - pub(crate) fn opaque(&self) -> Opaque { - Opaque(*self) - } -} - -/// When we are treating a type as opaque, it is just a blob with a `Layout`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct Opaque(pub(crate) Layout); - -impl Opaque { - /// Construct a new opaque type from the given clang type. - pub(crate) fn from_clang_ty( - ty: &clang::Type, - ctx: &BindgenContext, - ) -> Type { - let layout = Layout::new(ty.size(ctx), ty.align(ctx)); - let ty_kind = TypeKind::Opaque; - let is_const = ty.is_const(); - Type::new(None, Some(layout), ty_kind, is_const) - } - - /// Return the known rust type we should use to create a correctly-aligned - /// field with this layout. - pub(crate) fn known_rust_type_for_array( - &self, - ctx: &BindgenContext, - ) -> Option { - Layout::known_type_for_size(ctx, self.0.align) - } - - /// Return the array size that an opaque type for this layout should have if - /// we know the correct type for it, or `None` otherwise. - pub(crate) fn array_size(&self, ctx: &BindgenContext) -> Option { - if self.known_rust_type_for_array(ctx).is_some() { - Some(self.0.size / cmp::max(self.0.align, 1)) - } else { - None - } - } - - /// Return `true` if this opaque layout's array size will fit within the - /// maximum number of array elements that Rust allows deriving traits - /// with. Return `false` otherwise. - pub(crate) fn array_size_within_derive_limit( - &self, - ctx: &BindgenContext, - ) -> CanDerive { - if self - .array_size(ctx) - .map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - { - CanDerive::Yes - } else { - CanDerive::Manually - } } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/module.rs firefox-140.10.2/third_party/rust/bindgen/ir/module.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/module.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/module.rs Mon May 11 04:49:32 2026 @@ -84,8 +84,8 @@ let module_id = ctx.module(cursor); ctx.with_module(module_id, |ctx| { cursor.visit_sorted(ctx, |ctx, child| { - parse_one(ctx, child, Some(module_id.into())) - }) + parse_one(ctx, child, Some(module_id.into())); + }); }); Ok(ParseResult::AlreadyResolved(module_id.into())) diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/objc.rs firefox-140.10.2/third_party/rust/bindgen/ir/objc.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/objc.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/objc.rs Mon May 11 04:49:32 2026 @@ -17,20 +17,20 @@ use clang_sys::CXCursor_TemplateTypeParameter; use proc_macro2::{Ident, Span, TokenStream}; -/// Objective C interface as used in TypeKind +/// Objective-C interface as used in `TypeKind` /// -/// Also protocols and categories are parsed as this type +/// Also, protocols and categories are parsed as this type #[derive(Debug)] pub(crate) struct ObjCInterface { /// The name - /// like, NSObject + /// like, `NSObject` name: String, category: Option, is_protocol: bool, - /// The list of template names almost always, ObjectType or KeyType + /// The list of template names almost always, `ObjectType` or `KeyType` pub(crate) template_names: Vec, /// The list of protocols that this interface conforms to. @@ -39,7 +39,7 @@ /// The direct parent for this interface. pub(crate) parent_class: Option, - /// List of the methods defined in this interfae + /// List of the methods defined in this interface methods: Vec, class_methods: Vec, @@ -53,7 +53,7 @@ name: String, /// Method name as converted to rust - /// like, dataWithBytes_length_ + /// like, `dataWithBytes_length`_ rust_name: String, signature: FunctionSig, @@ -77,17 +77,17 @@ } /// The name - /// like, NSObject + /// like, `NSObject` pub(crate) fn name(&self) -> &str { self.name.as_ref() } /// Formats the name for rust - /// Can be like NSObject, but with categories might be like NSObject_NSCoderMethods - /// and protocols are like PNSObject + /// Can be like `NSObject`, but with categories might be like `NSObject_NSCoderMethods` + /// and protocols are like `PNSObject` pub(crate) fn rust_name(&self) -> String { if let Some(ref cat) = self.category { - format!("{}_{}", self.name(), cat) + format!("{}_{cat}", self.name()) } else if self.is_protocol { format!("P{}", self.name()) } else { @@ -137,7 +137,7 @@ CXCursor_ObjCClassRef => { if cursor.kind() == CXCursor_ObjCCategoryDecl { // We are actually a category extension, and we found the reference - // to the original interface, so name this interface approriately + // to the original interface, so name this interface appropriately interface.name = c.spelling(); interface.category = Some(cursor.spelling()); } @@ -147,8 +147,8 @@ let needle = format!("P{}", c.spelling()); let items_map = ctx.items(); debug!( - "Interface {} conforms to {}, find the item", - interface.name, needle + "Interface {} conforms to {needle}, find the item", + interface.name, ); for (id, item) in items_map { @@ -163,10 +163,7 @@ ty.name() ); if Some(needle.as_ref()) == ty.name() { - debug!( - "Found conforming protocol {:?}", - item - ); + debug!("Found conforming protocol {item:?}"); interface.conforms_to.push(id); break; } @@ -230,12 +227,12 @@ } /// Method name as converted to rust - /// like, dataWithBytes_length_ + /// like, `dataWithBytes_length`_ pub(crate) fn rust_name(&self) -> &str { self.rust_name.as_ref() } - /// Returns the methods signature as FunctionSig + /// Returns the methods signature as `FunctionSig` pub(crate) fn signature(&self) -> &FunctionSig { &self.signature } @@ -262,10 +259,7 @@ // unless it is `crate`, `self`, `super` or `Self`, so we try to add the `_` // suffix to it and parse it. if ["crate", "self", "super", "Self"].contains(&name) { - Some(Ident::new( - &format!("{}_", name), - Span::call_site(), - )) + Some(Ident::new(&format!("{name}_"), Span::call_site())) } else { Some(Ident::new(name, Span::call_site())) } @@ -278,11 +272,11 @@ Some( syn::parse_str::(name) .or_else(|err| { - syn::parse_str::(&format!("r#{}", name)) + syn::parse_str::(&format!("r#{name}")) .map_err(|_| err) }) .or_else(|err| { - syn::parse_str::(&format!("{}_", name)) + syn::parse_str::(&format!("{name}_")) .map_err(|_| err) }) .expect("Invalid identifier"), @@ -300,20 +294,15 @@ } // Check right amount of arguments - assert!( - args.len() == split_name.len() - 1, - "Incorrect method name or arguments for objc method, {:?} vs {:?}", - args, - split_name - ); + assert_eq!(args.len(), split_name.len() - 1, "Incorrect method name or arguments for objc method, {args:?} vs {split_name:?}"); // Get arguments without type signatures to pass to `msg_send!` let mut args_without_types = vec![]; - for arg in args.iter() { + for arg in args { let arg = arg.to_string(); let name_and_sig: Vec<&str> = arg.split(' ').collect(); let name = name_and_sig[0]; - args_without_types.push(Ident::new(name, Span::call_site())) + args_without_types.push(Ident::new(name, Span::call_site())); } let args = split_name.into_iter().zip(args_without_types).map( diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/template.rs firefox-140.10.2/third_party/rust/bindgen/ir/template.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/template.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/template.rs Mon May 11 04:49:32 2026 @@ -4,7 +4,7 @@ //! brief definitions: //! //! * "Template definition": a class/struct/alias/function definition that takes -//! generic template parameters. For example: +//! generic template parameters. For example: //! //! ```c++ //! template @@ -14,11 +14,11 @@ //! ``` //! //! * "Template instantiation": an instantiation is a use of a template with -//! concrete template arguments. For example, `List`. +//! concrete template arguments. For example, `List`. //! //! * "Template specialization": an alternative template definition providing a -//! custom definition for instantiations with the matching template -//! arguments. This C++ feature is unsupported by bindgen. For example: +//! custom definition for instantiations with the matching template +//! arguments. This C++ feature is unsupported by bindgen. For example: //! //! ```c++ //! template<> @@ -77,27 +77,23 @@ /// The following table depicts the results of each trait method when invoked on /// each of the declarations above: /// -/// +------+----------------------+--------------------------+-------------------------+---- -/// |Decl. | self_template_params | num_self_template_params | all_template_parameters | ... -/// +------+----------------------+--------------------------+-------------------------+---- -/// |Foo | T, U | 2 | T, U | ... -/// |Bar | V | 1 | T, U, V | ... -/// |Inner | | 0 | T, U | ... -/// |Lol | W | 1 | T, U, W | ... -/// |Wtf | X | 1 | T, U, X | ... -/// |Qux | | 0 | | ... -/// +------+----------------------+--------------------------+------------------------+---- +/// |Decl. | self_template_params | num_self_template_params | all_template_parameters | +/// |------|----------------------|--------------------------|-------------------------| +/// |Foo | T, U | 2 | T, U | +/// |Bar | V | 1 | T, U, V | +/// |Inner | | 0 | T, U | +/// |Lol | W | 1 | T, U, W | +/// |Wtf | X | 1 | T, U, X | +/// |Qux | | 0 | | /// -/// ----+------+-----+----------------------+ -/// ... |Decl. | ... | used_template_params | -/// ----+------+-----+----------------------+ -/// ... |Foo | ... | T, U | -/// ... |Bar | ... | V | -/// ... |Inner | ... | | -/// ... |Lol | ... | T | -/// ... |Wtf | ... | T | -/// ... |Qux | ... | | -/// ----+------+-----+----------------------+ +/// | Decl. | used_template_params | +/// |-------|----------------------| +/// | Foo | T, U | +/// | Bar | V | +/// | Inner | | +/// | Lol | T | +/// | Wtf | T | +/// | Qux | | pub(crate) trait TemplateParameters: Sized { /// Get the set of `ItemId`s that make up this template declaration's free /// template parameters. @@ -266,17 +262,14 @@ }) }; - let definition = match definition { - Some(def) => def, - None => { - if !ty.declaration().is_builtin() { - warn!( - "Could not find template definition for template \ + let Some(definition) = definition else { + if !ty.declaration().is_builtin() { + warn!( + "Could not find template definition for template \ instantiation" - ); - } - return None; + ); } + return None; }; let template_definition = diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/traversal.rs firefox-140.10.2/third_party/rust/bindgen/ir/traversal.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/traversal.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/traversal.rs Mon May 11 04:49:32 2026 @@ -235,7 +235,7 @@ /// outgoing edges might not have been fully traversed yet) in an active /// traversal. pub(crate) trait TraversalStorage<'ctx> { - /// Construct a new instance of this TraversalStorage, for a new traversal. + /// Construct a new instance of this `TraversalStorage`, for a new traversal. fn new(ctx: &'ctx BindgenContext) -> Self; /// Add the given item to the storage. If the item has never been seen @@ -287,8 +287,7 @@ } path.reverse(); panic!( - "Found reference to dangling id = {:?}\nvia path = {:?}", - item, path + "Found reference to dangling id = {item:?}\nvia path = {path:?}" ); } @@ -345,7 +344,7 @@ F: FnMut(ItemId, EdgeKind), { fn visit_kind(&mut self, item: ItemId, kind: EdgeKind) { - (*self)(item, kind) + (*self)(item, kind); } } @@ -438,7 +437,7 @@ let is_newly_discovered = self.seen.add(self.currently_traversing, item); if is_newly_discovered { - self.queue.push(item) + self.queue.push(item); } } } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/ty.rs firefox-140.10.2/third_party/rust/bindgen/ir/ty.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/ty.rs Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/ty.rs Mon May 11 04:49:32 2026 @@ -6,7 +6,7 @@ use super::enum_ty::Enum; use super::function::FunctionSig; use super::item::{IsOpaque, Item}; -use super::layout::{Layout, Opaque}; +use super::layout::Layout; use super::objc::ObjCInterface; use super::template::{ AsTemplateParam, TemplateInstantiation, TemplateParameters, @@ -67,6 +67,17 @@ } } + /// Construct an opaque item from a clang type. + pub(crate) fn new_opaque_from_clang_ty( + ty: &clang::Type, + ctx: &BindgenContext, + ) -> Self { + let layout = Layout::new(ty.size(ctx), ty.align(ctx)); + let ty_kind = TypeKind::Opaque; + let is_const = ty.is_const(); + Type::new(None, Some(layout), ty_kind, is_const) + } + /// Which kind of type is this? pub(crate) fn kind(&self) -> &TypeKind { &self.kind @@ -243,16 +254,16 @@ } /// Takes `name`, and returns a suitable identifier representation for it. - fn sanitize_name(name: &str) -> Cow { + fn sanitize_name(name: &str) -> Cow<'_, str> { if clang::is_valid_identifier(name) { return Cow::Borrowed(name); } - let name = name.replace(|c| c == ' ' || c == ':' || c == '.', "_"); + let name = name.replace([' ', ':', '.'], "_"); Cow::Owned(name) } - /// Get this type's santizied name. + /// Get this type's sanitized name. pub(crate) fn sanitized_name<'a>( &'a self, ctx: &BindgenContext, @@ -261,7 +272,7 @@ TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))), TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))), TypeKind::Array(inner, length) => { - Some((inner, format!("array{}", length).into())) + Some((inner, format!("array{length}").into())) } _ => None, }; @@ -269,13 +280,13 @@ ctx.resolve_item(inner) .expect_type() .sanitized_name(ctx) - .map(|name| format!("{}_{}", prefix, name).into()) + .map(|name| format!("{prefix}_{name}").into()) } else { self.name().map(Self::sanitize_name) } } - /// See safe_canonical_type. + /// See [`Self::safe_canonical_type`]. pub(crate) fn canonical_type<'tr>( &'tr self, ctx: &'tr BindgenContext, @@ -471,7 +482,7 @@ #[test] fn is_invalid_type_param_valid() { let ty = Type::new(Some("foo".into()), None, TypeKind::TypeParam, false); - assert!(!ty.is_invalid_type_param()) + assert!(!ty.is_invalid_type_param()); } #[test] @@ -482,38 +493,38 @@ TypeKind::TypeParam, false, ); - assert!(!ty.is_invalid_type_param()) + assert!(!ty.is_invalid_type_param()); } #[test] fn is_invalid_type_param_valid_unnamed_kind() { let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false); - assert!(!ty.is_invalid_type_param()) + assert!(!ty.is_invalid_type_param()); } #[test] fn is_invalid_type_param_invalid_start() { let ty = Type::new(Some("1foo".into()), None, TypeKind::TypeParam, false); - assert!(ty.is_invalid_type_param()) + assert!(ty.is_invalid_type_param()); } #[test] -fn is_invalid_type_param_invalid_remaing() { +fn is_invalid_type_param_invalid_remaining() { let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false); - assert!(ty.is_invalid_type_param()) + assert!(ty.is_invalid_type_param()); } #[test] -#[should_panic] +#[should_panic(expected = "Unnamed named type")] fn is_invalid_type_param_unnamed() { let ty = Type::new(None, None, TypeKind::TypeParam, false); - assert!(ty.is_invalid_type_param()) + assert!(ty.is_invalid_type_param()); } #[test] fn is_invalid_type_param_empty_name() { - let ty = Type::new(Some("".into()), None, TypeKind::TypeParam, false); - assert!(ty.is_invalid_type_param()) + let ty = Type::new(Some(String::new()), None, TypeKind::TypeParam, false); + assert!(ty.is_invalid_type_param()); } impl TemplateParameters for Type { @@ -582,7 +593,7 @@ /// A compound type, that is, a class, struct, or union. Comp(CompInfo), - /// An opaque type that we just don't understand. All usage of this shoulf + /// An opaque type that we just don't understand. All usage of this should /// result in an opaque blob of bytes generated from the containing type's /// layout. Opaque, @@ -623,7 +634,7 @@ /// A pointer to an Apple block. BlockPointer(TypeId), - /// A reference to a type, as in: int& foo(). + /// A reference to a type, as in: int& `foo()`. Reference(TypeId), /// An instantiation of an abstract template definition with a set of @@ -634,15 +645,10 @@ /// itself, and postpones its resolution. /// /// These are gone in a phase after parsing where these are mapped to - /// already known types, and are converted to ResolvedTypeRef. + /// already known types, and are converted to `ResolvedTypeRef`. /// /// see tests/headers/typeref.hpp to see somewhere where this is a problem. - UnresolvedTypeRef( - clang::Type, - clang::Cursor, - /* parent_id */ - Option, - ), + UnresolvedTypeRef(clang::Type, Cursor, /* parent_id */ Option), /// An indirection to another type. /// @@ -685,7 +691,7 @@ Some(location), ); if let Some(ty) = already_resolved { - debug!("{:?} already resolved: {:?}", ty, location); + debug!("{ty:?} already resolved: {location:?}"); return Ok(ParseResult::AlreadyResolved(ty.into())); } } @@ -700,8 +706,7 @@ }; debug!( - "from_clang_ty: {:?}, ty: {:?}, loc: {:?}", - potential_id, ty, location + "from_clang_ty: {potential_id:?}, ty: {ty:?}, loc: {location:?}" ); debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types()); @@ -711,7 +716,7 @@ let mut ty_kind = ty.kind(); match location.kind() { CXCursor_ObjCProtocolDecl | CXCursor_ObjCCategoryDecl => { - ty_kind = CXType_ObjCInterface + ty_kind = CXType_ObjCInterface; } _ => {} } @@ -743,7 +748,7 @@ opaque type instead." ); return Ok(ParseResult::New( - Opaque::from_clang_ty(&canonical_ty, ctx), + Self::new_opaque_from_clang_ty(&canonical_ty, ctx), None, )); } @@ -776,7 +781,7 @@ // etc. !canonical_ty.spelling().contains("type-parameter") => { - debug!("Looking for canonical type: {:?}", canonical_ty); + debug!("Looking for canonical type: {canonical_ty:?}"); return Self::from_clang_ty( potential_id, &canonical_ty, @@ -797,10 +802,7 @@ // Same here, with template specialisations we can safely // assume this is a Comp(..) } else if ty.is_fully_instantiated_template() { - debug!( - "Template specialization: {:?}, {:?} {:?}", - ty, location, canonical_ty - ); + debug!("Template specialization: {ty:?}, {location:?} {canonical_ty:?}"); let complex = CompInfo::from_ty( potential_id, ty, @@ -869,20 +871,17 @@ Some(location), ctx, ); - match complex { - Ok(complex) => TypeKind::Comp(complex), - Err(_) => { - warn!( - "Could not create complex type \ - from class template or base \ - specifier, using opaque blob" - ); - let opaque = - Opaque::from_clang_ty(ty, ctx); - return Ok(ParseResult::New( - opaque, None, - )); - } + if let Ok(complex) = complex { + TypeKind::Comp(complex) + } else { + warn!( + "Could not create complex type \ + from class template or base \ + specifier, using opaque blob" + ); + let opaque = + Self::new_opaque_from_clang_ty(ty, ctx); + return Ok(ParseResult::New(opaque, None)); } } CXCursor_TypeAliasTemplateDecl => { @@ -930,16 +929,12 @@ CXChildVisit_Continue }); - let inner_type = match inner { - Ok(inner) => inner, - Err(..) => { - warn!( - "Failed to parse template alias \ - {:?}", - location - ); - return Err(ParseError::Continue); - } + let Ok(inner_type) = inner else { + warn!( + "Failed to parse template alias \ + {location:?}" + ); + return Err(ParseError::Continue); }; TypeKind::TemplateAlias(inner_type, args) @@ -948,13 +943,7 @@ let referenced = location.referenced().unwrap(); let referenced_ty = referenced.cur_type(); - debug!( - "TemplateRef: location = {:?}; referenced = \ - {:?}; referenced_ty = {:?}", - location, - referenced, - referenced_ty - ); + debug!("TemplateRef: location = {location:?}; referenced = {referenced:?}; referenced_ty = {referenced_ty:?}"); return Self::from_clang_ty( potential_id, @@ -969,11 +958,7 @@ let referenced_ty = referenced.cur_type(); let declaration = referenced_ty.declaration(); - debug!( - "TypeRef: location = {:?}; referenced = \ - {:?}; referenced_ty = {:?}", - location, referenced, referenced_ty - ); + debug!("TypeRef: location = {location:?}; referenced = {referenced:?}; referenced_ty = {referenced_ty:?}"); let id = Item::from_ty_or_ref_with_id( potential_id, @@ -991,16 +976,11 @@ } _ => { if ty.kind() == CXType_Unexposed { - warn!( - "Unexposed type {:?}, recursing inside, \ - loc: {:?}", - ty, - location - ); + warn!("Unexposed type {ty:?}, recursing inside, loc: {location:?}"); return Err(ParseError::Recurse); } - warn!("invalid type {:?}", ty); + warn!("invalid type {ty:?}"); return Err(ParseError::Continue); } } @@ -1008,7 +988,7 @@ } CXType_Auto => { if canonical_ty == *ty { - debug!("Couldn't find deduced type: {:?}", ty); + debug!("Couldn't find deduced type: {ty:?}"); return Err(ParseError::Continue); } @@ -1092,7 +1072,7 @@ Item::from_ty_or_ref(inner, location, None, ctx); if inner_id == potential_id { warn!( - "Generating oqaque type instead of self-referential \ + "Generating opaque type instead of self-referential \ typedef"); // This can happen if we bail out of recursive situations // within the clang parsing. @@ -1148,7 +1128,7 @@ TypeKind::Comp(complex) } - CXType_Vector => { + CXType_Vector | CXType_ExtVector => { let inner = Item::from_ty( ty.elem_type().as_ref().unwrap(), location, @@ -1167,6 +1147,18 @@ .expect("Not able to resolve array element?"); TypeKind::Array(inner, ty.num_elements().unwrap()) } + CXType_Atomic => { + // TODO(emilio): Maybe we can preserve the "is atomic" bit somehow and generate + // something more useful... But for now this is better than panicking or + // generating nothing. + return Self::from_clang_ty( + potential_id, + &ty.atomic_value_type(), + location, + parent_id, + ctx, + ); + } CXType_Elaborated => { return Self::from_clang_ty( potential_id, @@ -1191,10 +1183,8 @@ } _ => { warn!( - "unsupported type: kind = {:?}; ty = {:?}; at {:?}", + "unsupported type: kind = {:?}; ty = {ty:?}; at {location:?}", ty.kind(), - ty, - location ); return Err(ParseError::Continue); } @@ -1205,8 +1195,7 @@ let is_const = ty.is_const() || (ty.kind() == CXType_ConstantArray && - ty.elem_type() - .map_or(false, |element| element.is_const())); + ty.elem_type().is_some_and(|element| element.is_const())); let ty = Type::new(name, layout, kind, is_const); // TODO: maybe declaration.canonical()? @@ -1221,10 +1210,7 @@ where T: Tracer, { - if self - .name() - .map_or(false, |name| context.is_stdint_type(name)) - { + if self.name().is_some_and(|name| context.is_stdint_type(name)) { // These types are special-cased in codegen and don't need to be traversed. return; } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/ir/var.rs firefox-140.10.2/third_party/rust/bindgen/ir/var.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/ir/var.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/ir/var.rs Mon May 11 04:49:32 2026 @@ -113,11 +113,7 @@ } if let Some(ref mangled) = self.mangled_name { - writeln!( - out, - "mangled name{}", - mangled - )?; + writeln!(out, "mangled name{mangled}")?; } Ok(()) @@ -129,35 +125,32 @@ ctx.options().default_macro_constant_type == MacroTypeVariation::Signed { - if value < i32::min_value() as i64 || value > i32::max_value() as i64 { + if value < i64::from(i32::MIN) || value > i64::from(i32::MAX) { IntKind::I64 } else if !ctx.options().fit_macro_constants || - value < i16::min_value() as i64 || - value > i16::max_value() as i64 + value < i64::from(i16::MIN) || + value > i64::from(i16::MAX) { IntKind::I32 - } else if value < i8::min_value() as i64 || - value > i8::max_value() as i64 - { + } else if value < i64::from(i8::MIN) || value > i64::from(i8::MAX) { IntKind::I16 } else { IntKind::I8 } - } else if value > u32::max_value() as i64 { + } else if value > i64::from(u32::MAX) { IntKind::U64 - } else if !ctx.options().fit_macro_constants || - value > u16::max_value() as i64 + } else if !ctx.options().fit_macro_constants || value > i64::from(u16::MAX) { IntKind::U32 - } else if value > u8::max_value() as i64 { + } else if value > i64::from(u8::MAX) { IntKind::U16 } else { IntKind::U8 } } -/// Parses tokens from a CXCursor_MacroDefinition pointing into a function-like -/// macro, and calls the func_macro callback. +/// Parses tokens from a `CXCursor_MacroDefinition` pointing into a function-like +/// macro, and calls the `func_macro` callback. fn handle_function_macro( cursor: &clang::Cursor, callbacks: &dyn crate::callbacks::ParseCallbacks, @@ -206,9 +199,8 @@ let value = parse_macro(ctx, &cursor); - let (id, value) = match value { - Some(v) => v, - None => return Err(ParseError::Continue), + let Some((id, value)) = value else { + return Err(ParseError::Continue); }; assert!(!id.is_empty(), "Empty macro name?"); @@ -242,10 +234,7 @@ assert_eq!(c.len_utf8(), 1); c as u8 } - CChar::Raw(c) => { - assert!(c <= ::std::u8::MAX as u64); - c as u8 - } + CChar::Raw(c) => u8::try_from(c).unwrap(), }; (TypeKind::Int(IntKind::U8), VarType::Char(c)) @@ -315,7 +304,7 @@ ([CXType_ConstantArray, CXType_IncompleteArray] .contains(&ty.kind()) && ty.elem_type() - .map_or(false, |element| element.is_const())); + .is_some_and(|element| element.is_const())); let ty = match Item::from_ty(&ty, cursor, None, ctx) { Ok(ty) => ty, @@ -324,7 +313,7 @@ matches!(ty.kind(), CXType_Auto | CXType_Unexposed), "Couldn't resolve constant type, and it \ wasn't an nondeductible auto type or unexposed \ - type!" + type: {ty:?}" ); return Err(e); } @@ -338,17 +327,17 @@ .safe_resolve_type(ty) .and_then(|t| t.safe_canonical_type(ctx)); - let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); - let is_float = canonical_ty.map_or(false, |t| t.is_float()); + let is_integer = canonical_ty.is_some_and(|t| t.is_integer()); + let is_float = canonical_ty.is_some_and(|t| t.is_float()); // TODO: We could handle `char` more gracefully. // TODO: Strings, though the lookup is a bit more hard (we need // to look at the canonical type of the pointee too, and check // is char, u8, or i8 I guess). let value = if is_integer { - let kind = match *canonical_ty.unwrap().kind() { - TypeKind::Int(kind) => kind, - _ => unreachable!(), + let TypeKind::Int(kind) = *canonical_ty.unwrap().kind() + else { + unreachable!() }; let mut val = cursor.evaluate().and_then(|v| v.as_int()); @@ -389,20 +378,66 @@ } } +/// This function uses a [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] to parse each +/// macro that cannot be parsed by the normal bindgen process for `#define`s. +/// +/// To construct the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit], first precompiled +/// headers are generated for all input headers. An empty temporary `.c` file is generated to pass +/// to the translation unit. On the evaluation of each macro, a [`String`] is generated with the +/// new contents of the empty file and passed in for reparsing. The precompiled headers and +/// preservation of the [`FallbackTranslationUnit`][clang::FallbackTranslationUnit] across macro +/// evaluations are both optimizations that have significantly improved the performance. +fn parse_macro_clang_fallback( + ctx: &mut BindgenContext, + cursor: &clang::Cursor, +) -> Option<(Vec, cexpr::expr::EvalResult)> { + if !ctx.options().clang_macro_fallback { + return None; + } + + let ftu = ctx.try_ensure_fallback_translation_unit()?; + let contents = format!("int main() {{ {}; }}", cursor.spelling()); + ftu.reparse(&contents).ok()?; + // Children of root node of AST + let root_children = ftu.translation_unit().cursor().collect_children(); + // Last child in root is function declaration + // Should be FunctionDecl + let main_func = root_children.last()?; + // Children should all be statements in function declaration + let all_stmts = main_func.collect_children(); + // First child in all_stmts should be the statement containing the macro to evaluate + // Should be CompoundStmt + let macro_stmt = all_stmts.first()?; + // Children should all be expressions from the compound statement + let paren_exprs = macro_stmt.collect_children(); + // First child in all_exprs is the expression utilizing the given macro to be evaluated + // Should be ParenExpr + let paren = paren_exprs.first()?; + + Some(( + cursor.spelling().into_bytes(), + cexpr::expr::EvalResult::Int(Wrapping(paren.evaluate()?.as_int()?)), + )) +} + /// Try and parse a macro using all the macros parsed until now. fn parse_macro( - ctx: &BindgenContext, + ctx: &mut BindgenContext, cursor: &clang::Cursor, ) -> Option<(Vec, cexpr::expr::EvalResult)> { use cexpr::expr; - let cexpr_tokens = cursor.cexpr_tokens(); + let mut cexpr_tokens = cursor.cexpr_tokens(); + for callbacks in &ctx.options().parse_callbacks { + callbacks.modify_macro(&cursor.spelling(), &mut cexpr_tokens); + } + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); match parser.macro_definition(&cexpr_tokens) { Ok((_, (id, val))) => Some((id.into(), val)), - _ => None, + _ => parse_macro_clang_fallback(ctx, cursor), } } @@ -443,15 +478,15 @@ fn duplicated_macro_diagnostic( macro_name: &str, - _location: crate::clang::SourceLocation, + _location: clang::SourceLocation, _ctx: &BindgenContext, ) { - warn!("Duplicated macro definition: {}", macro_name); + warn!("Duplicated macro definition: {macro_name}"); #[cfg(feature = "experimental")] // FIXME (pvdrz & amanjeev): This diagnostic message shows way too often to be actually // useful. We have to change the logic where this function is called to be able to emit this - // message only when the duplication is an actuall issue. + // message only when the duplication is an actual issue. // // If I understood correctly, `bindgen` ignores all `#undef` directives. Meaning that this: // ```c @@ -480,7 +515,7 @@ slice.with_source(source); Diagnostic::default() - .with_title("Duplicated macro definition.", Level::Warn) + .with_title("Duplicated macro definition.", Level::Warning) .add_slice(slice) .add_annotation("This macro had a duplicate.", Level::Note) .display(); diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/lib.rs firefox-140.10.2/third_party/rust/bindgen/lib.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/lib.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/lib.rs Mon May 11 04:49:32 2026 @@ -19,8 +19,6 @@ #[macro_use] extern crate bitflags; #[macro_use] -extern crate lazy_static; -#[macro_use] extern crate quote; #[cfg(feature = "logging")] @@ -52,12 +50,11 @@ pub use codegen::{ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, }; -#[cfg(feature = "__cli")] -pub use features::RUST_TARGET_STRINGS; -pub use features::{RustTarget, LATEST_STABLE_RUST}; +pub use features::{RustEdition, RustTarget, LATEST_STABLE_RUST}; pub use ir::annotations::FieldVisibilityKind; pub use ir::function::Abi; -pub use regex_set::RegexSet; +#[cfg(feature = "__cli")] +pub use options::cli::builder_from_flags; use codegen::CodegenError; use features::RustFeatures; @@ -73,6 +70,7 @@ use std::ffi::OsStr; use std::fs::{File, OpenOptions}; use std::io::{self, Write}; +use std::mem::size_of; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::rc::Rc; @@ -88,10 +86,12 @@ const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern"; fn file_is_cpp(name_file: &str) -> bool { - name_file.ends_with(".hpp") || - name_file.ends_with(".hxx") || - name_file.ends_with(".hh") || - name_file.ends_with(".h++") + Path::new(name_file).extension().is_some_and(|ext| { + ext.eq_ignore_ascii_case("hpp") || + ext.eq_ignore_ascii_case("hxx") || + ext.eq_ignore_ascii_case("hh") || + ext.eq_ignore_ascii_case("h++") + }) } fn args_are_cpp(clang_args: &[Box]) -> bool { @@ -144,7 +144,7 @@ self.contains(CodegenConfig::VARS) } - /// Returns true if methds should be generated. + /// Returns true if methods should be generated. pub fn methods(self) -> bool { self.contains(CodegenConfig::METHODS) } @@ -194,7 +194,7 @@ "rustfmt" => Ok(Self::Rustfmt), #[cfg(feature = "prettyplease")] "prettyplease" => Ok(Self::Prettyplease), - _ => Err(format!("`{}` is not a valid formatter", s)), + _ => Err(format!("`{s}` is not a valid formatter")), } } } @@ -208,7 +208,7 @@ Self::Prettyplease => "prettyplease", }; - s.fmt(f) + std::fmt::Display::fmt(&s, f) } } @@ -238,6 +238,7 @@ /// 2. [`bitfield_enum()`](#method.bitfield_enum) /// 3. [`newtype_enum()`](#method.newtype_enum) /// 4. [`rustified_enum()`](#method.rustified_enum) +/// 5. [`rustified_non_exhaustive_enum()`](#method.rustified_non_exhaustive_enum) /// /// For each C enum, bindgen tries to match the pattern in the following order: /// @@ -300,12 +301,11 @@ parse_callbacks: &[Rc], ) -> Vec { // Add any extra arguments from the environment to the clang command line. - let extra_clang_args = match get_target_dependent_env_var( + let Some(extra_clang_args) = get_target_dependent_env_var( parse_callbacks, "BINDGEN_EXTRA_CLANG_ARGS", - ) { - None => return vec![], - Some(s) => s, + ) else { + return vec![]; }; // Try to parse it with shell quoting. If we fail, make it one single big argument. @@ -318,6 +318,22 @@ impl Builder { /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result { + // Keep rust_features synced with rust_target + self.options.rust_features = match self.options.rust_edition { + Some(edition) => { + if !edition.is_available(self.options.rust_target) { + return Err(BindgenError::UnsupportedEdition( + edition, + self.options.rust_target, + )); + } + RustFeatures::new(self.options.rust_target, edition) + } + None => { + RustFeatures::new_with_latest_edition(self.options.rust_target) + } + }; + // Add any extra arguments from the environment to the clang command line. self.options.clang_args.extend( get_extra_clang_args(&self.options.parse_callbacks) @@ -331,6 +347,18 @@ } // Transform input headers to arguments on the clang command line. + self.options.fallback_clang_args = self + .options + .clang_args + .iter() + .filter(|arg| { + !arg.starts_with("-MMD") && + !arg.starts_with("-MD") && + !arg.starts_with("--write-user-dependencies") && + !arg.starts_with("--user-dependencies") + }) + .cloned() + .collect::>(); self.options.clang_args.extend( self.options.input_headers [..self.options.input_headers.len().saturating_sub(1)] @@ -346,7 +374,7 @@ }) .collect::>(); - Bindings::generate(self.options, input_unsaved_files) + Bindings::generate(self.options, &input_unsaved_files) } /// Preprocess and dump the input header files to disk. @@ -527,25 +555,11 @@ for regex_set in self.abi_overrides.values_mut().chain(regex_sets) { regex_set.build(record_matches); } - - let rust_target = self.rust_target; - #[allow(deprecated)] - if rust_target <= RustTarget::Stable_1_30 { - deprecated_target_diagnostic(rust_target, self); - } - - // Disable `untagged_union` if the target does not support it. - if !self.rust_features.untagged_union { - self.untagged_union = false; - } } /// Update rust target version pub fn set_rust_target(&mut self, rust_target: RustTarget) { self.rust_target = rust_target; - - // Keep rust_features synced with rust_target - self.rust_features = rust_target.into(); } /// Get features supported by target Rust version @@ -560,7 +574,7 @@ self.parse_callbacks .iter() .filter_map(|cb| f(cb.as_ref())) - .last() + .next_back() } fn all_callbacks( @@ -579,36 +593,15 @@ fn process_comment(&self, comment: &str) -> String { let comment = comment::preprocess(comment); - self.parse_callbacks - .last() - .and_then(|cb| cb.process_comment(&comment)) + self.last_callback(|cb| cb.process_comment(&comment)) .unwrap_or(comment) } } -fn deprecated_target_diagnostic(target: RustTarget, _options: &BindgenOptions) { - warn!("The {} Rust target is deprecated. If you have a need to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", target); - - #[cfg(feature = "experimental")] - if _options.emit_diagnostics { - use crate::diagnostics::{Diagnostic, Level}; - - let mut diagnostic = Diagnostic::default(); - diagnostic.with_title( - format!("The {} Rust target is deprecated.", target), - Level::Warn, - ); - diagnostic.add_annotation( - "This Rust target was passed to `--rust-target`", - Level::Info, - ); - diagnostic.add_annotation("If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues", Level::Help); - diagnostic.display(); - } -} - #[cfg(feature = "runtime")] fn ensure_libclang_is_loaded() { + use std::sync::{Arc, OnceLock}; + if clang_sys::is_loaded() { return; } @@ -617,17 +610,14 @@ // doesn't get dropped prematurely, nor is loaded multiple times // across different threads. - lazy_static! { - static ref LIBCLANG: std::sync::Arc = { - clang_sys::load().expect("Unable to find libclang"); - clang_sys::get_library().expect( - "We just loaded libclang and it had better still be \ - here!", - ) - }; - } + static LIBCLANG: OnceLock> = OnceLock::new(); + let libclang = LIBCLANG.get_or_init(|| { + clang_sys::load().expect("Unable to find libclang"); + clang_sys::get_library() + .expect("We just loaded libclang and it had better still be here!") + }); - clang_sys::set_library(Some(LIBCLANG.clone())); + clang_sys::set_library(Some(libclang.clone())); } #[cfg(not(feature = "runtime"))] @@ -647,6 +637,8 @@ ClangDiagnostic(String), /// Code generation reported an error. Codegen(CodegenError), + /// The passed edition is not available on that Rust target. + UnsupportedEdition(RustEdition, RustTarget), } impl std::fmt::Display for BindgenError { @@ -662,11 +654,14 @@ write!(f, "header '{}' does not exist.", h.display()) } BindgenError::ClangDiagnostic(message) => { - write!(f, "clang diagnosed error: {}", message) + write!(f, "clang diagnosed error: {message}") } BindgenError::Codegen(err) => { - write!(f, "codegen error: {}", err) + write!(f, "codegen error: {err}") } + BindgenError::UnsupportedEdition(edition, target) => { + write!(f, "edition {edition} is not available on Rust {target}") + } } } } @@ -686,35 +681,46 @@ // Some architecture triplets are different between rust and libclang, see #1211 // and duplicates. fn rust_to_clang_target(rust_target: &str) -> Box { - if rust_target.starts_with("aarch64-apple-") { - let mut clang_target = "arm64-apple-".to_owned(); - clang_target - .push_str(rust_target.strip_prefix("aarch64-apple-").unwrap()); - return clang_target.into(); - } else if rust_target.starts_with("riscv64gc-") { - let mut clang_target = "riscv64-".to_owned(); - clang_target.push_str(rust_target.strip_prefix("riscv64gc-").unwrap()); - return clang_target.into(); - } else if rust_target.ends_with("-espidf") { - let mut clang_target = - rust_target.strip_suffix("-espidf").unwrap().to_owned(); - clang_target.push_str("-elf"); - if clang_target.starts_with("riscv32imc-") { - clang_target = "riscv32-".to_owned() + - clang_target.strip_prefix("riscv32imc-").unwrap(); + const TRIPLE_HYPHENS_MESSAGE: &str = "Target triple should contain hyphens"; + + let mut triple: Vec<&str> = rust_target.split_terminator('-').collect(); + + assert!(!triple.is_empty(), "{}", TRIPLE_HYPHENS_MESSAGE); + triple.resize(4, ""); + + // RISC-V + if triple[0].starts_with("riscv32") { + triple[0] = "riscv32"; + } else if triple[0].starts_with("riscv64") { + triple[0] = "riscv64"; + } + + // Apple + if triple[1] == "apple" { + if triple[0] == "aarch64" { + triple[0] = "arm64"; } - return clang_target.into(); - } else if rust_target.starts_with("riscv32imc-") { - let mut clang_target = "riscv32-".to_owned(); - clang_target.push_str(rust_target.strip_prefix("riscv32imc-").unwrap()); - return clang_target.into(); - } else if rust_target.starts_with("riscv32imac-") { - let mut clang_target = "riscv32-".to_owned(); - clang_target - .push_str(rust_target.strip_prefix("riscv32imac-").unwrap()); - return clang_target.into(); + if triple[3] == "sim" { + triple[3] = "simulator"; + } } - rust_target.into() + + // ESP-IDF + if triple[2] == "espidf" { + triple[2] = "elf"; + } + + triple + .iter() + .skip(1) + .fold(triple[0].to_string(), |triple, part| { + if part.is_empty() { + triple + } else { + triple + "-" + part + } + }) + .into() } /// Returns the effective target, and whether it was explicitly specified on the @@ -747,11 +753,23 @@ /// Generate bindings for the given options. pub(crate) fn generate( mut options: BindgenOptions, - input_unsaved_files: Vec, + input_unsaved_files: &[clang::UnsavedFile], ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] + match clang_sys::get_library().unwrap().version() { + None => { + warn!("Could not detect a Clang version, make sure you are using libclang 9 or newer"); + } + Some(version) => { + if version < clang_sys::Version::V9_0 { + warn!("Detected Clang version {version:?} which is unsupported and can cause invalid code generation, use libclang 9 or newer"); + } + } + } + + #[cfg(feature = "runtime")] debug!( "Generating bindings, libclang at {}", clang_sys::get_library().unwrap().path().display() @@ -775,9 +793,9 @@ if !explicit_target && !is_host_build { options.clang_args.insert( 0, - format!("--target={}", effective_target).into_boxed_str(), + format!("--target={effective_target}").into_boxed_str(), ); - }; + } fn detect_include_paths(options: &mut BindgenOptions) { if !options.detect_include_paths { @@ -819,19 +837,17 @@ }; debug!( - "Trying to find clang with flags: {:?}", - clang_args_for_clang_sys + "Trying to find clang with flags: {clang_args_for_clang_sys:?}" ); - let clang = match clang_sys::support::Clang::find( + let Some(clang) = clang_sys::support::Clang::find( None, &clang_args_for_clang_sys, - ) { - None => return, - Some(clang) => clang, + ) else { + return; }; - debug!("Found clang: {:?}", clang); + debug!("Found clang: {clang:?}"); // Whether we are working with C or C++ inputs. let is_cpp = args_are_cpp(&options.clang_args) || @@ -844,7 +860,7 @@ }; if let Some(search_paths) = search_paths { - for path in search_paths.into_iter() { + for path in search_paths { if let Ok(path) = path.into_os_string().into_string() { options.clang_args.push("-isystem".into()); options.clang_args.push(path.into_boxed_str()); @@ -887,21 +903,19 @@ if idx != 0 || !options.input_headers.is_empty() { options.clang_args.push("-include".into()); } - options.clang_args.push(f.name.to_str().unwrap().into()) + options.clang_args.push(f.name.to_str().unwrap().into()); } - debug!("Fixed-up options: {:?}", options); + debug!("Fixed-up options: {options:?}"); let time_phases = options.time_phases; - let mut context = BindgenContext::new(options, &input_unsaved_files); + let mut context = BindgenContext::new(options, input_unsaved_files); if is_host_build { debug_assert_eq!( context.target_pointer_size(), - std::mem::size_of::<*mut ()>(), - "{:?} {:?}", - effective_target, - HOST_TARGET + size_of::<*mut ()>(), + "{effective_target:?} {HOST_TARGET:?}" ); } @@ -934,13 +948,13 @@ if !self.options.disable_header_comment { let version = option_env!("CARGO_PKG_VERSION").unwrap_or("(unknown version)"); - writeln!( + write!( writer, - "/* automatically generated by rust-bindgen {version} */{NL}", + "/* automatically generated by rust-bindgen {version} */{NL}{NL}", )?; } - for line in self.options.raw_lines.iter() { + for line in &self.options.raw_lines { writer.write_all(line.as_bytes())?; writer.write_all(NL.as_bytes())?; } @@ -955,8 +969,7 @@ } Err(err) => { eprintln!( - "Failed to run rustfmt: {} (non-fatal, continuing)", - err + "Failed to run rustfmt: {err} (non-fatal, continuing)" ); writer.write_all(self.module.to_string().as_bytes())?; } @@ -965,25 +978,17 @@ } /// Gets the rustfmt path to rustfmt the generated bindings. - fn rustfmt_path(&self) -> io::Result> { + fn rustfmt_path(&self) -> Cow<'_, Path> { debug_assert!(matches!(self.options.formatter, Formatter::Rustfmt)); if let Some(ref p) = self.options.rustfmt_path { - return Ok(Cow::Borrowed(p)); + Cow::Borrowed(p) + } else if let Ok(rustfmt) = env::var("RUSTFMT") { + Cow::Owned(rustfmt.into()) + } else { + // No rustfmt binary was specified, so assume that the binary is called + // "rustfmt" and that it is in the user's PATH. + Cow::Borrowed(Path::new("rustfmt")) } - if let Ok(rustfmt) = env::var("RUSTFMT") { - return Ok(Cow::Owned(rustfmt.into())); - } - #[cfg(feature = "which-rustfmt")] - match which::which("rustfmt") { - Ok(p) => Ok(Cow::Owned(p)), - Err(e) => { - Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))) - } - } - #[cfg(not(feature = "which-rustfmt"))] - // No rustfmt binary was specified, so assume that the binary is called - // "rustfmt" and that it is in the user's PATH. - Ok(Cow::Owned("rustfmt".into())) } /// Formats a token stream with the formatter set up in `BindgenOptions`. @@ -1003,7 +1008,7 @@ Formatter::Rustfmt => (), } - let rustfmt = self.rustfmt_path()?; + let rustfmt = self.rustfmt_path(); let mut cmd = Command::new(&*rustfmt); cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); @@ -1017,6 +1022,12 @@ cmd.args(["--config-path", path]); } + let edition = self + .options + .rust_edition + .unwrap_or_else(|| self.options.rust_target.latest_edition()); + cmd.args(["--edition", &format!("{edition}")]); + let mut child = cmd.spawn()?; let mut child_stdin = child.stdin.take().unwrap(); let mut child_stdout = child.stdout.take().unwrap(); @@ -1065,14 +1076,14 @@ } fn rustfmt_non_fatal_error_diagnostic(msg: &str, _options: &BindgenOptions) { - warn!("{}", msg); + warn!("{msg}"); #[cfg(feature = "experimental")] if _options.emit_diagnostics { use crate::diagnostics::{Diagnostic, Level}; Diagnostic::default() - .with_title(msg, Level::Warn) + .with_title(msg, Level::Warning) .add_annotation( "The bindings will be generated but not formatted.", Level::Note, @@ -1124,7 +1135,7 @@ use clang_sys::*; let mut error = None; - for d in context.translation_unit().diags().iter() { + for d in &context.translation_unit().diags() { let msg = d.format(); let is_err = d.severity() >= CXDiagnostic_Error; if is_err { @@ -1132,7 +1143,7 @@ error.push_str(&msg); error.push('\n'); } else { - eprintln!("clang diag: {}", msg); + eprintln!("clang diag: {msg}"); } } @@ -1144,10 +1155,10 @@ if context.options().emit_ast { fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { - if !cur.is_builtin() { - clang::ast_dump(cur, 0) - } else { + if cur.is_builtin() { CXChildVisit_Continue + } else { + clang::ast_dump(cur, 0) } } cursor.visit(|cur| dump_if_not_builtin(&cur)); @@ -1155,11 +1166,12 @@ let root = context.root_module(); context.with_module(root, |ctx| { - cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, None)) + cursor.visit_sorted(ctx, |ctx, child| parse_one(ctx, child, None)); }); - assert!( - context.current_module() == context.root_module(), + assert_eq!( + context.current_module(), + context.root_module(), "How did this happen?" ); Ok(()) @@ -1182,7 +1194,7 @@ let raw_v: String = clang::extract_clang_version(); let split_v: Option> = raw_v .split_whitespace() - .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit())) + .find(|t| t.chars().next().is_some_and(|v| v.is_ascii_digit())) .map(|v| v.split('.').collect()); if let Some(v) = split_v { if v.len() >= 2 { @@ -1195,7 +1207,7 @@ }; } } - }; + } ClangVersion { parsed: None, full: raw_v.clone(), @@ -1205,11 +1217,11 @@ fn env_var + AsRef>( parse_callbacks: &[Rc], key: K, -) -> Result { +) -> Result { for callback in parse_callbacks { callback.read_env_var(key.as_ref()); } - std::env::var(key) + env::var(key) } /// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. @@ -1218,12 +1230,12 @@ var: &str, ) -> Option { if let Ok(target) = env_var(parse_callbacks, "TARGET") { - if let Ok(v) = env_var(parse_callbacks, format!("{}_{}", var, target)) { + if let Ok(v) = env_var(parse_callbacks, format!("{var}_{target}")) { return Some(v); } if let Ok(v) = env_var( parse_callbacks, - format!("{}_{}", var, target.replace('-', "_")), + format!("{var}_{}", target.replace('-', "_")), ) { return Some(v); } @@ -1232,7 +1244,7 @@ env_var(parse_callbacks, var).ok() } -/// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed +/// A `ParseCallbacks` implementation that will act on file includes by echoing a rerun-if-changed /// line and on env variable usage by echoing a rerun-if-env-changed line /// /// When running inside a `build.rs` script, this can be used to make cargo invalidate the @@ -1285,24 +1297,24 @@ impl callbacks::ParseCallbacks for CargoCallbacks { fn header_file(&self, filename: &str) { if self.rerun_on_header_files { - println!("cargo:rerun-if-changed={}", filename); + println!("cargo:rerun-if-changed={filename}"); } } fn include_file(&self, filename: &str) { - println!("cargo:rerun-if-changed={}", filename); + println!("cargo:rerun-if-changed={filename}"); } fn read_env_var(&self, key: &str) { - println!("cargo:rerun-if-env-changed={}", key); + println!("cargo:rerun-if-env-changed={key}"); } } -/// Test command_line_flag function. +/// Test `command_line_flag` function. #[test] fn commandline_flag_unit_test_function() { //Test 1 - let bindings = crate::builder(); + let bindings = builder(); let command_line_flags = bindings.command_line_flags(); let test_cases = [ @@ -1318,7 +1330,7 @@ assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); //Test 2 - let bindings = crate::builder() + let bindings = builder() .header("input_header") .allowlist_type("Distinct_Type") .allowlist_function("safe_function"); @@ -1338,7 +1350,7 @@ .iter() .map(|&x| x.into()) .collect::>(); - println!("{:?}", command_line_flags); + println!("{command_line_flags:?}"); assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); } @@ -1358,6 +1370,10 @@ "riscv64-unknown-linux-gnu" ); assert_eq!( + rust_to_clang_target("riscv64imac-unknown-none-elf").as_ref(), + "riscv64-unknown-none-elf" + ); + assert_eq!( rust_to_clang_target("riscv32imc-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); @@ -1365,6 +1381,14 @@ rust_to_clang_target("riscv32imac-unknown-none-elf").as_ref(), "riscv32-unknown-none-elf" ); + assert_eq!( + rust_to_clang_target("riscv32imafc-unknown-none-elf").as_ref(), + "riscv32-unknown-none-elf" + ); + assert_eq!( + rust_to_clang_target("riscv32i-unknown-none-elf").as_ref(), + "riscv32-unknown-none-elf" + ); } #[test] @@ -1376,5 +1400,21 @@ assert_eq!( rust_to_clang_target("xtensa-esp32-espidf").as_ref(), "xtensa-esp32-elf" + ); +} + +#[test] +fn test_rust_to_clang_target_simulator() { + assert_eq!( + rust_to_clang_target("aarch64-apple-ios-sim").as_ref(), + "arm64-apple-ios-simulator" + ); + assert_eq!( + rust_to_clang_target("aarch64-apple-tvos-sim").as_ref(), + "arm64-apple-tvos-simulator" + ); + assert_eq!( + rust_to_clang_target("aarch64-apple-watchos-sim").as_ref(), + "arm64-apple-watchos-simulator" ); } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/log_stubs.rs firefox-140.10.2/third_party/rust/bindgen/log_stubs.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/log_stubs.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/log_stubs.rs Mon May 11 04:49:32 2026 @@ -1,5 +1,6 @@ #![allow(unused)] +#[clippy::format_args] macro_rules! log { (target: $target:expr, $lvl:expr, $($arg:tt)+) => {{ let _ = $target; @@ -10,22 +11,27 @@ let _ = format_args!($($arg)+); }}; } +#[clippy::format_args] macro_rules! error { (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) }; ($($arg:tt)+) => { log!("", $($arg)+) }; } +#[clippy::format_args] macro_rules! warn { (target: $target:expr, $($arg:tt)*) => { log!(target: $target, "", $($arg)*) }; ($($arg:tt)*) => { log!("", $($arg)*) }; } +#[clippy::format_args] macro_rules! info { (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) }; ($($arg:tt)+) => { log!("", $($arg)+) }; } +#[clippy::format_args] macro_rules! debug { (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) }; ($($arg:tt)+) => { log!("", $($arg)+) }; } +#[clippy::format_args] macro_rules! trace { (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) }; ($($arg:tt)+) => { log!("", $($arg)+) }; diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/options/as_args.rs firefox-140.10.2/third_party/rust/bindgen/options/as_args.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/options/as_args.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/bindgen/options/as_args.rs Mon May 11 04:49:32 2026 @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::RegexSet; +use crate::regex_set::RegexSet; /// Trait used to turn [`crate::BindgenOptions`] fields into CLI args. pub(super) trait AsArgs { diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/options/cli.rs firefox-140.10.2/third_party/rust/bindgen/options/cli.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/options/cli.rs Thu Jan 1 01:00:00 1970 +++ firefox-140.10.2/third_party/rust/bindgen/options/cli.rs Mon May 11 04:49:32 2026 @@ -0,0 +1,1151 @@ +#![allow(unused_qualifications)] // Clap somehow generates a lot of these + +use crate::{ + builder, + callbacks::{ + AttributeInfo, DeriveInfo, ItemInfo, ParseCallbacks, TypeKind, + }, + features::{RustEdition, EARLIEST_STABLE_RUST}, + regex_set::RegexSet, + Abi, AliasVariation, Builder, CodegenConfig, EnumVariation, + FieldVisibilityKind, Formatter, MacroTypeVariation, NonCopyUnionStyle, + RustTarget, +}; +use clap::{ + error::{Error, ErrorKind}, + CommandFactory, Parser, +}; +use proc_macro2::TokenStream; +use std::io; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::{fs::File, process::exit}; + +fn rust_target_help() -> String { + format!( + "Version of the Rust compiler to target. Any Rust version after {EARLIEST_STABLE_RUST} is supported. Defaults to {}.", + RustTarget::default() + ) +} + +fn rust_edition_help() -> String { + format!("Rust edition to target. Defaults to the latest edition supported by the chosen Rust target. Possible values: ({}). ", RustEdition::ALL.map(|e| e.to_string()).join("|")) +} + +fn parse_codegen_config( + what_to_generate: &str, +) -> Result { + let mut config = CodegenConfig::empty(); + for what in what_to_generate.split(',') { + match what { + "functions" => config.insert(CodegenConfig::FUNCTIONS), + "types" => config.insert(CodegenConfig::TYPES), + "vars" => config.insert(CodegenConfig::VARS), + "methods" => config.insert(CodegenConfig::METHODS), + "constructors" => config.insert(CodegenConfig::CONSTRUCTORS), + "destructors" => config.insert(CodegenConfig::DESTRUCTORS), + otherwise => { + return Err(Error::raw( + ErrorKind::InvalidValue, + format!("Unknown codegen item kind: {otherwise}"), + )); + } + } + } + + Ok(config) +} + +fn parse_rustfmt_config_path(path_str: &str) -> Result { + let path = Path::new(path_str); + + if !path.is_absolute() { + return Err(Error::raw( + ErrorKind::InvalidValue, + "--rustfmt-configuration-file needs to be an absolute path!", + )); + } + + if path.to_str().is_none() { + return Err(Error::raw( + ErrorKind::InvalidUtf8, + "--rustfmt-configuration-file contains non-valid UTF8 characters.", + )); + } + + Ok(path.to_path_buf()) +} + +fn parse_abi_override(abi_override: &str) -> Result<(Abi, String), Error> { + let (regex, abi_str) = abi_override + .rsplit_once('=') + .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; + + let abi = abi_str + .parse() + .map_err(|err| Error::raw(ErrorKind::InvalidValue, err))?; + + Ok((abi, regex.to_owned())) +} + +fn parse_custom_derive( + custom_derive: &str, +) -> Result<(Vec, String), Error> { + let (regex, derives) = custom_derive + .rsplit_once('=') + .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; + + let derives = derives.split(',').map(|s| s.to_owned()).collect(); + + Ok((derives, regex.to_owned())) +} + +fn parse_custom_attribute( + custom_attribute: &str, +) -> Result<(Vec, String), Error> { + let mut brace_level = 0; + let (regex, attributes) = custom_attribute + .rsplit_once(|c| { + match c { + ']' => brace_level += 1, + '[' => brace_level -= 1, + _ => {} + } + c == '=' && brace_level == 0 + }) + .ok_or_else(|| Error::raw(ErrorKind::InvalidValue, "Missing `=`"))?; + + let mut brace_level = 0; + let attributes = attributes + .split(|c| { + match c { + ']' => brace_level += 1, + '[' => brace_level -= 1, + _ => {} + } + c == ',' && brace_level == 0 + }) + .map(|s| s.to_owned()) + .collect::>(); + + for attribute in &attributes { + if let Err(err) = TokenStream::from_str(attribute) { + return Err(Error::raw(ErrorKind::InvalidValue, err)); + } + } + + Ok((attributes, regex.to_owned())) +} + +#[derive(Parser, Debug)] +#[clap( + about = "Generates Rust bindings from C/C++ headers.", + override_usage = "bindgen
-- ...", + trailing_var_arg = true +)] +#[allow(clippy::doc_markdown)] +struct BindgenCommand { + /// C or C++ header file. + header: Option, + /// Path to write depfile to. + #[arg(long)] + depfile: Option, + /// The default STYLE of code used to generate enums. + #[arg(long, value_name = "STYLE")] + default_enum_style: Option, + /// Mark any enum whose name matches REGEX as a set of bitfield flags. + #[arg(long, value_name = "REGEX")] + bitfield_enum: Vec, + /// Mark any enum whose name matches REGEX as a newtype. + #[arg(long, value_name = "REGEX")] + newtype_enum: Vec, + /// Mark any enum whose name matches REGEX as a global newtype. + #[arg(long, value_name = "REGEX")] + newtype_global_enum: Vec, + /// Mark any enum whose name matches REGEX as a Rust enum. + #[arg(long, value_name = "REGEX")] + rustified_enum: Vec, + /// Mark any enum whose name matches REGEX as a non-exhaustive Rust enum. + #[arg(long, value_name = "REGEX")] + rustified_non_exhaustive_enum: Vec, + /// Mark any enum whose name matches REGEX as a series of constants. + #[arg(long, value_name = "REGEX")] + constified_enum: Vec, + /// Mark any enum whose name matches REGEX as a module of constants. + #[arg(long, value_name = "REGEX")] + constified_enum_module: Vec, + /// The default signed/unsigned TYPE for C macro constants. + #[arg(long, value_name = "TYPE")] + default_macro_constant_type: Option, + /// The default STYLE of code used to generate typedefs. + #[arg(long, value_name = "STYLE")] + default_alias_style: Option, + /// Mark any typedef alias whose name matches REGEX to use normal type aliasing. + #[arg(long, value_name = "REGEX")] + normal_alias: Vec, + /// Mark any typedef alias whose name matches REGEX to have a new type generated for it. + #[arg(long, value_name = "REGEX")] + new_type_alias: Vec, + /// Mark any typedef alias whose name matches REGEX to have a new type with Deref and DerefMut to the inner type. + #[arg(long, value_name = "REGEX")] + new_type_alias_deref: Vec, + /// The default STYLE of code used to generate unions with non-Copy members. Note that ManuallyDrop was first stabilized in Rust 1.20.0. + #[arg(long, value_name = "STYLE")] + default_non_copy_union_style: Option, + /// Mark any union whose name matches REGEX and who has a non-Copy member to use a bindgen-generated wrapper for fields. + #[arg(long, value_name = "REGEX")] + bindgen_wrapper_union: Vec, + /// Mark any union whose name matches REGEX and who has a non-Copy member to use ManuallyDrop (stabilized in Rust 1.20.0) for fields. + #[arg(long, value_name = "REGEX")] + manually_drop_union: Vec, + /// Mark TYPE as hidden. + #[arg(long, value_name = "TYPE")] + blocklist_type: Vec, + /// Mark FUNCTION as hidden. + #[arg(long, value_name = "FUNCTION")] + blocklist_function: Vec, + /// Mark ITEM as hidden. + #[arg(long, value_name = "ITEM")] + blocklist_item: Vec, + /// Mark FILE as hidden. + #[arg(long, value_name = "FILE")] + blocklist_file: Vec, + /// Mark VAR as hidden. + #[arg(long, value_name = "VAR")] + blocklist_var: Vec, + /// Avoid generating layout tests for any type. + #[arg(long)] + no_layout_tests: bool, + /// Avoid deriving Copy on any type. + #[arg(long)] + no_derive_copy: bool, + /// Avoid deriving Debug on any type. + #[arg(long)] + no_derive_debug: bool, + /// Avoid deriving Default on any type. + #[arg(long, hide = true)] + no_derive_default: bool, + /// Create a Debug implementation if it cannot be derived automatically. + #[arg(long)] + impl_debug: bool, + /// Create a PartialEq implementation if it cannot be derived automatically. + #[arg(long)] + impl_partialeq: bool, + /// Derive Default on any type. + #[arg(long)] + with_derive_default: bool, + /// Derive Hash on any type. + #[arg(long)] + with_derive_hash: bool, + /// Derive PartialEq on any type. + #[arg(long)] + with_derive_partialeq: bool, + /// Derive PartialOrd on any type. + #[arg(long)] + with_derive_partialord: bool, + /// Derive Eq on any type. + #[arg(long)] + with_derive_eq: bool, + /// Derive Ord on any type. + #[arg(long)] + with_derive_ord: bool, + /// Avoid including doc comments in the output, see: + #[arg(long)] + no_doc_comments: bool, + /// Disable allowlisting types recursively. This will cause bindgen to emit Rust code that won't compile! See the `bindgen::Builder::allowlist_recursively` method's documentation for details. + #[arg(long)] + no_recursive_allowlist: bool, + /// Use extern crate instead of use for objc. + #[arg(long)] + objc_extern_crate: bool, + /// Generate block signatures instead of void pointers. + #[arg(long)] + generate_block: bool, + /// Generate string constants as `&CStr` instead of `&[u8]`. + #[arg(long)] + generate_cstr: bool, + /// Use extern crate instead of use for block. + #[arg(long)] + block_extern_crate: bool, + /// Do not trust the libclang-provided mangling + #[arg(long)] + distrust_clang_mangling: bool, + /// Output bindings for builtin definitions, e.g. __builtin_va_list. + #[arg(long)] + builtins: bool, + /// Use the given PREFIX before raw types instead of ::std::os::raw. + #[arg(long, value_name = "PREFIX")] + ctypes_prefix: Option, + /// Use the given PREFIX for anonymous fields. + #[arg(long, value_name = "PREFIX")] + anon_fields_prefix: Option, + /// Time the different bindgen phases and print to stderr + #[arg(long)] + time_phases: bool, + /// Output the Clang AST for debugging purposes. + #[arg(long)] + emit_clang_ast: bool, + /// Output our internal IR for debugging purposes. + #[arg(long)] + emit_ir: bool, + /// Dump a graphviz dot file to PATH. + #[arg(long, value_name = "PATH")] + emit_ir_graphviz: Option, + /// Enable support for C++ namespaces. + #[arg(long)] + enable_cxx_namespaces: bool, + /// Disable namespacing via mangling, causing bindgen to generate names like `Baz` instead of `foo_bar_Baz` for an input name `foo::bar::Baz`. + #[arg(long)] + disable_name_namespacing: bool, + /// Disable nested struct naming, causing bindgen to generate names like `bar` instead of `foo_bar` for a nested definition `struct foo { struct bar { } b; };`. + #[arg(long)] + disable_nested_struct_naming: bool, + /// Disable support for native Rust unions. + #[arg(long)] + disable_untagged_union: bool, + /// Suppress insertion of bindgen's version identifier into generated bindings. + #[arg(long)] + disable_header_comment: bool, + /// Do not generate bindings for functions or methods. This is useful when you only care about struct layouts. + #[arg(long)] + ignore_functions: bool, + /// Generate only given items, split by commas. Valid values are `functions`,`types`, `vars`, `methods`, `constructors` and `destructors`. + #[arg(long, value_parser = parse_codegen_config)] + generate: Option, + /// Do not generate bindings for methods. + #[arg(long)] + ignore_methods: bool, + /// Do not automatically convert floats to f32/f64. + #[arg(long)] + no_convert_floats: bool, + /// Do not prepend the enum name to constant or newtype variants. + #[arg(long)] + no_prepend_enum_name: bool, + /// Do not try to detect default include paths + #[arg(long)] + no_include_path_detection: bool, + /// Try to fit macro constants into types smaller than u32/i32 + #[arg(long)] + fit_macro_constant_types: bool, + /// Mark TYPE as opaque. + #[arg(long, value_name = "TYPE")] + opaque_type: Vec, + /// Write Rust bindings to OUTPUT. + #[arg(long, short, value_name = "OUTPUT")] + output: Option, + /// Add a raw line of Rust code at the beginning of output. + #[arg(long)] + raw_line: Vec, + /// Add a RAW_LINE of Rust code to a given module with name MODULE_NAME. + #[arg(long, number_of_values = 2, value_names = ["MODULE_NAME", "RAW_LINE"])] + module_raw_line: Vec, + #[arg(long, help = rust_target_help())] + rust_target: Option, + #[arg(long, value_name = "EDITION", help = rust_edition_help())] + rust_edition: Option, + /// Use types from Rust core instead of std. + #[arg(long)] + use_core: bool, + /// Conservatively generate inline namespaces to avoid name conflicts. + #[arg(long)] + conservative_inline_namespaces: bool, + /// Allowlist all the free-standing functions matching REGEX. Other non-allowlisted functions will not be generated. + #[arg(long, value_name = "REGEX")] + allowlist_function: Vec, + /// Generate inline functions. + #[arg(long)] + generate_inline_functions: bool, + /// Only generate types matching REGEX. Other non-allowlisted types will not be generated. + #[arg(long, value_name = "REGEX")] + allowlist_type: Vec, + /// Allowlist all the free-standing variables matching REGEX. Other non-allowlisted variables will not be generated. + #[arg(long, value_name = "REGEX")] + allowlist_var: Vec, + /// Allowlist all contents of PATH. + #[arg(long, value_name = "PATH")] + allowlist_file: Vec, + /// Allowlist all items matching REGEX. Other non-allowlisted items will not be generated. + #[arg(long, value_name = "REGEX")] + allowlist_item: Vec, + /// Print verbose error messages. + #[arg(long)] + verbose: bool, + /// Preprocess and dump the input header files to disk. Useful when debugging bindgen, using C-Reduce, or when filing issues. The resulting file will be named something like `__bindgen.i` or `__bindgen.ii`. + #[arg(long)] + dump_preprocessed_input: bool, + /// Do not record matching items in the regex sets. This disables reporting of unused items. + #[arg(long)] + no_record_matches: bool, + /// Do not bind size_t as usize (useful on platforms where those types are incompatible). + #[arg(long = "no-size_t-is-usize")] + no_size_t_is_usize: bool, + /// Do not format the generated bindings with rustfmt. This option is deprecated, please use + /// `--formatter=none` instead. + #[arg(long)] + no_rustfmt_bindings: bool, + /// Which FORMATTER should be used for the bindings + #[arg( + long, + value_name = "FORMATTER", + conflicts_with = "no_rustfmt_bindings" + )] + formatter: Option, + /// The absolute PATH to the rustfmt configuration file. The configuration file will be used for formatting the bindings. This parameter sets `formatter` to `rustfmt`. + #[arg(long, value_name = "PATH", conflicts_with = "no_rustfmt_bindings", value_parser=parse_rustfmt_config_path)] + rustfmt_configuration_file: Option, + /// Avoid deriving PartialEq for types matching REGEX. + #[arg(long, value_name = "REGEX")] + no_partialeq: Vec, + /// Avoid deriving Copy and Clone for types matching REGEX. + #[arg(long, value_name = "REGEX")] + no_copy: Vec, + /// Avoid deriving Debug for types matching REGEX. + #[arg(long, value_name = "REGEX")] + no_debug: Vec, + /// Avoid deriving/implementing Default for types matching REGEX. + #[arg(long, value_name = "REGEX")] + no_default: Vec, + /// Avoid deriving Hash for types matching REGEX. + #[arg(long, value_name = "REGEX")] + no_hash: Vec, + /// Add `#[must_use]` annotation to types matching REGEX. + #[arg(long, value_name = "REGEX")] + must_use_type: Vec, + /// Enables detecting unexposed attributes in functions (slow). Used to generate `#[must_use]` annotations. + #[arg(long)] + enable_function_attribute_detection: bool, + /// Use `*const [T; size]` instead of `*const T` for C arrays + #[arg(long)] + use_array_pointers_in_arguments: bool, + /// The NAME to be used in a #[link(wasm_import_module = ...)] statement + #[arg(long, value_name = "NAME")] + wasm_import_module_name: Option, + /// Use dynamic loading mode with the given library NAME. + #[arg(long, value_name = "NAME")] + dynamic_loading: Option, + /// Require successful linkage to all functions in the library. + #[arg(long)] + dynamic_link_require_all: bool, + /// Prefix the name of exported symbols. + #[arg(long)] + prefix_link_name: Option, + /// Makes generated bindings `pub` only for items if the items are publicly accessible in C++. + #[arg(long)] + respect_cxx_access_specs: bool, + /// Always translate enum integer types to native Rust integer types. + #[arg(long)] + translate_enum_integer_types: bool, + /// Generate types with C style naming. + #[arg(long)] + c_naming: bool, + /// Always output explicit padding fields. + #[arg(long)] + explicit_padding: bool, + /// Always be specific about the 'receiver' of a virtual function. + #[arg(long)] + use_specific_virtual_function_receiver: bool, + /// Use distinct char16_t + #[arg(long)] + use_distinct_char16_t: bool, + /// Output C++ overloaded operators + #[arg(long)] + represent_cxx_operators: bool, + /// Enables generation of vtable functions. + #[arg(long)] + vtable_generation: bool, + /// Enables sorting of code generation in a predefined manner. + #[arg(long)] + sort_semantically: bool, + /// Deduplicates extern blocks. + #[arg(long)] + merge_extern_blocks: bool, + /// Overrides the ABI of functions matching REGEX. The OVERRIDE value must be of the shape REGEX=ABI where ABI can be one of C, stdcall, efiapi, fastcall, thiscall, aapcs, win64 or C-unwind<.> + #[arg(long, value_name = "OVERRIDE", value_parser = parse_abi_override)] + override_abi: Vec<(Abi, String)>, + /// Wrap unsafe operations in unsafe blocks. + #[arg(long)] + wrap_unsafe_ops: bool, + /// Enable fallback for clang macro parsing. + #[arg(long)] + clang_macro_fallback: bool, + /// Set path for temporary files generated by fallback for clang macro parsing. + #[arg(long)] + clang_macro_fallback_build_dir: Option, + /// Use DSTs to represent structures with flexible array members. + #[arg(long)] + flexarray_dst: bool, + /// Derive custom traits on any kind of type. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a comma-separated list of derive macros. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] + with_derive_custom: Vec<(Vec, String)>, + /// Derive custom traits on a `struct`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a comma-separated list of derive macros. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] + with_derive_custom_struct: Vec<(Vec, String)>, + /// Derive custom traits on an `enum`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a comma-separated list of derive macros. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] + with_derive_custom_enum: Vec<(Vec, String)>, + /// Derive custom traits on a `union`. The CUSTOM value must be of the shape REGEX=DERIVE where DERIVE is a comma-separated list of derive macros. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_derive)] + with_derive_custom_union: Vec<(Vec, String)>, + /// Add custom attributes on any kind of type. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a comma-separated list of attributes. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] + with_attribute_custom: Vec<(Vec, String)>, + /// Add custom attributes on a `struct`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a comma-separated list of attributes. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] + with_attribute_custom_struct: Vec<(Vec, String)>, + /// Add custom attributes on an `enum`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a comma-separated list of attributes. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] + with_attribute_custom_enum: Vec<(Vec, String)>, + /// Add custom attributes on a `union`. The CUSTOM value must be of the shape REGEX=ATTRIBUTE where ATTRIBUTE is a comma-separated list of attributes. + #[arg(long, value_name = "CUSTOM", value_parser = parse_custom_attribute)] + with_attribute_custom_union: Vec<(Vec, String)>, + /// Generate wrappers for `static` and `static inline` functions. + #[arg(long)] + wrap_static_fns: bool, + /// Sets the PATH for the source file that must be created due to the presence of `static` and + /// `static inline` functions. + #[arg(long, value_name = "PATH")] + wrap_static_fns_path: Option, + /// Sets the SUFFIX added to the extern wrapper functions generated for `static` and `static + /// inline` functions. + #[arg(long, value_name = "SUFFIX")] + wrap_static_fns_suffix: Option, + /// Set the default VISIBILITY of fields, including bitfields and accessor methods for + /// bitfields. This flag is ignored if the `--respect-cxx-access-specs` flag is used. + #[arg(long, value_name = "VISIBILITY")] + default_visibility: Option, + /// Whether to generate C++ functions marked with "=delete" even though they + /// can't be called. + #[arg(long)] + generate_deleted_functions: bool, + /// Whether to generate C++ "pure virtual" functions even though they can't + /// be called. + #[arg(long)] + generate_pure_virtual_functions: bool, + /// Whether to generate C++ private functions even though they can't + /// be called. + #[arg(long)] + generate_private_functions: bool, + /// Whether to emit diagnostics or not. + #[cfg(feature = "experimental")] + #[arg(long, requires = "experimental")] + emit_diagnostics: bool, + /// Generates completions for the specified SHELL, sends them to `stdout` and exits. + #[arg(long, value_name = "SHELL")] + generate_shell_completions: Option, + /// Enables experimental features. + #[arg(long)] + experimental: bool, + /// Prints the version, and exits + #[arg(short = 'V', long)] + version: bool, + /// Arguments to be passed straight through to clang. + clang_args: Vec, +} + +/// Construct a new [`Builder`](./struct.Builder.html) from command line flags. +pub fn builder_from_flags( + args: I, +) -> Result<(Builder, Box, bool), io::Error> +where + I: Iterator, +{ + let command = BindgenCommand::parse_from(args); + + let BindgenCommand { + header, + depfile, + default_enum_style, + bitfield_enum, + newtype_enum, + newtype_global_enum, + rustified_enum, + rustified_non_exhaustive_enum, + constified_enum, + constified_enum_module, + default_macro_constant_type, + default_alias_style, + normal_alias, + new_type_alias, + new_type_alias_deref, + default_non_copy_union_style, + bindgen_wrapper_union, + manually_drop_union, + blocklist_type, + blocklist_function, + blocklist_item, + blocklist_file, + blocklist_var, + no_layout_tests, + no_derive_copy, + no_derive_debug, + no_derive_default, + impl_debug, + impl_partialeq, + with_derive_default, + with_derive_hash, + with_derive_partialeq, + with_derive_partialord, + with_derive_eq, + with_derive_ord, + no_doc_comments, + no_recursive_allowlist, + objc_extern_crate, + generate_block, + generate_cstr, + block_extern_crate, + distrust_clang_mangling, + builtins, + ctypes_prefix, + anon_fields_prefix, + time_phases, + emit_clang_ast, + emit_ir, + emit_ir_graphviz, + enable_cxx_namespaces, + disable_name_namespacing, + disable_nested_struct_naming, + disable_untagged_union, + disable_header_comment, + ignore_functions, + generate, + ignore_methods, + no_convert_floats, + no_prepend_enum_name, + no_include_path_detection, + fit_macro_constant_types, + opaque_type, + output, + raw_line, + module_raw_line, + rust_target, + rust_edition, + use_core, + conservative_inline_namespaces, + allowlist_function, + generate_inline_functions, + allowlist_type, + allowlist_var, + allowlist_file, + allowlist_item, + verbose, + dump_preprocessed_input, + no_record_matches, + no_size_t_is_usize, + no_rustfmt_bindings, + formatter, + rustfmt_configuration_file, + no_partialeq, + no_copy, + no_debug, + no_default, + no_hash, + must_use_type, + enable_function_attribute_detection, + use_array_pointers_in_arguments, + wasm_import_module_name, + dynamic_loading, + dynamic_link_require_all, + prefix_link_name, + respect_cxx_access_specs, + translate_enum_integer_types, + c_naming, + explicit_padding, + use_specific_virtual_function_receiver, + use_distinct_char16_t, + represent_cxx_operators, + vtable_generation, + sort_semantically, + merge_extern_blocks, + override_abi, + wrap_unsafe_ops, + clang_macro_fallback, + clang_macro_fallback_build_dir, + flexarray_dst, + with_derive_custom, + with_derive_custom_struct, + with_derive_custom_enum, + with_derive_custom_union, + with_attribute_custom, + with_attribute_custom_struct, + with_attribute_custom_enum, + with_attribute_custom_union, + wrap_static_fns, + wrap_static_fns_path, + wrap_static_fns_suffix, + default_visibility, + generate_deleted_functions, + generate_pure_virtual_functions, + generate_private_functions, + #[cfg(feature = "experimental")] + emit_diagnostics, + generate_shell_completions, + experimental: _, + version, + clang_args, + } = command; + + if let Some(shell) = generate_shell_completions { + clap_complete::generate( + shell, + &mut BindgenCommand::command(), + "bindgen", + &mut io::stdout(), + ); + + exit(0) + } + + if version { + println!( + "bindgen {}", + option_env!("CARGO_PKG_VERSION").unwrap_or("unknown") + ); + if verbose { + println!("Clang: {}", crate::clang_version().full); + } + + exit(0) + } + + if header.is_none() { + return Err(io::Error::new(io::ErrorKind::Other, "Header not found")); + } + + let mut builder = builder(); + + #[derive(Debug)] + struct PrefixLinkNameCallback { + prefix: String, + } + + impl ParseCallbacks for PrefixLinkNameCallback { + fn generated_link_name_override( + &self, + item_info: ItemInfo<'_>, + ) -> Option { + let mut prefix = self.prefix.clone(); + prefix.push_str(item_info.name); + Some(prefix) + } + } + + #[derive(Debug)] + struct CustomDeriveCallback { + derives: Vec, + kind: Option, + regex_set: RegexSet, + } + + impl ParseCallbacks for CustomDeriveCallback { + fn cli_args(&self) -> Vec { + let mut args = vec![]; + + let flag = match &self.kind { + None => "--with-derive-custom", + Some(TypeKind::Struct) => "--with-derive-custom-struct", + Some(TypeKind::Enum) => "--with-derive-custom-enum", + Some(TypeKind::Union) => "--with-derive-custom-union", + }; + + let derives = self.derives.join(","); + + for item in self.regex_set.get_items() { + args.extend_from_slice(&[ + flag.to_owned(), + format!("{item}={derives}"), + ]); + } + + args + } + + fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec { + if self.kind.map_or(true, |kind| kind == info.kind) && + self.regex_set.matches(info.name) + { + return self.derives.clone(); + } + vec![] + } + } + + #[derive(Debug)] + struct CustomAttributeCallback { + attributes: Vec, + kind: Option, + regex_set: RegexSet, + } + + impl ParseCallbacks for CustomAttributeCallback { + fn cli_args(&self) -> Vec { + let mut args = vec![]; + + let flag = match &self.kind { + None => "--with-attribute-custom", + Some(TypeKind::Struct) => "--with-attribute-custom-struct", + Some(TypeKind::Enum) => "--with-attribute-custom-enum", + Some(TypeKind::Union) => "--with-attribute-custom-union", + }; + + let attributes = self.attributes.join(","); + + for item in self.regex_set.get_items() { + args.extend_from_slice(&[ + flag.to_owned(), + format!("{item}={attributes}"), + ]); + } + + args + } + + fn add_attributes(&self, info: &AttributeInfo<'_>) -> Vec { + if self.kind.map_or(true, |kind| kind == info.kind) && + self.regex_set.matches(info.name) + { + return self.attributes.clone(); + } + vec![] + } + } + + /// Macro used to apply CLI arguments to a builder. + /// + /// This is done by passing an identifier for each argument and a function to be applied over + /// the builder. For example: + /// ```rust,ignore + /// fn apply_arg(builder: Builder, arg_value: Value) -> Builder { + /// todo!() + /// } + /// + /// apply_args!( + /// builder { + /// arg => apply_arg, + /// } + /// ); + /// ``` + /// + /// If the identifier of the argument is the same as an already existing builder method then + /// you can omit the second part: + /// ```rust,ignore + /// apply_args!( + /// builder { + /// arg + /// } + /// ); + /// ``` + /// Which expands to the same code as: + /// ```rust,ignore + /// apply_args!( + /// builder { + /// arg => Builder::arg, + /// } + /// ); + /// ``` + macro_rules! apply_args { + ($builder:ident {}) => { $builder }; + ($builder:ident {$arg:ident => $function:expr, $($token:tt)*}) => { + { + $builder = CliArg::apply($arg, $builder, $function); + apply_args!($builder {$($token)*}) + } + }; + ($builder:ident {$arg:ident, $($token:tt)*}) => { + { + $builder = CliArg::apply($arg, $builder, Builder::$arg); + apply_args!($builder {$($token)*}) + } + } + } + + builder = apply_args!( + builder { + header, + rust_target, + rust_edition, + default_enum_style, + bitfield_enum, + newtype_enum, + newtype_global_enum, + rustified_enum, + rustified_non_exhaustive_enum, + constified_enum, + constified_enum_module, + default_macro_constant_type, + default_alias_style, + normal_alias => Builder::type_alias, + new_type_alias, + new_type_alias_deref, + default_non_copy_union_style, + bindgen_wrapper_union, + manually_drop_union, + blocklist_type, + blocklist_function, + blocklist_item, + blocklist_file, + blocklist_var, + builtins => |b, _| b.emit_builtins(), + no_layout_tests => |b, _| b.layout_tests(false), + no_derive_copy => |b, _| b.derive_copy(false), + no_derive_debug => |b, _| b.derive_debug(false), + impl_debug, + impl_partialeq, + with_derive_default => Builder::derive_default, + with_derive_hash => Builder::derive_hash, + with_derive_partialeq => Builder::derive_partialeq, + with_derive_partialord => Builder::derive_partialord, + with_derive_eq => Builder::derive_eq, + with_derive_ord => Builder::derive_ord, + no_derive_default => |b, _| b.derive_default(false), + no_prepend_enum_name => |b, _| b.prepend_enum_name(false), + no_include_path_detection => |b, _| b.detect_include_paths(false), + fit_macro_constant_types => Builder::fit_macro_constants, + time_phases, + use_array_pointers_in_arguments => Builder::array_pointers_in_arguments, + wasm_import_module_name, + ctypes_prefix, + anon_fields_prefix, + generate => Builder::with_codegen_config, + emit_clang_ast => |b, _| b.emit_clang_ast(), + emit_ir => |b, _| b.emit_ir(), + emit_ir_graphviz, + enable_cxx_namespaces => |b, _| b.enable_cxx_namespaces(), + enable_function_attribute_detection => |b, _| b.enable_function_attribute_detection(), + disable_name_namespacing => |b, _| b.disable_name_namespacing(), + disable_nested_struct_naming => |b, _| b.disable_nested_struct_naming(), + disable_untagged_union => |b, _| b.disable_untagged_union(), + disable_header_comment => |b, _| b.disable_header_comment(), + ignore_functions => |b, _| b.ignore_functions(), + ignore_methods => |b, _| b.ignore_methods(), + no_convert_floats => |b, _| b.no_convert_floats(), + no_doc_comments => |b, _| b.generate_comments(false), + no_recursive_allowlist => |b, _| b.allowlist_recursively(false), + objc_extern_crate, + generate_block, + generate_cstr, + block_extern_crate, + opaque_type, + raw_line, + use_core => |b, _| b.use_core(), + distrust_clang_mangling => |b, _| b.trust_clang_mangling(false), + conservative_inline_namespaces => |b, _| b.conservative_inline_namespaces(), + generate_inline_functions, + allowlist_function, + allowlist_type, + allowlist_var, + allowlist_file, + allowlist_item, + clang_args => Builder::clang_arg, + no_record_matches => |b, _| b.record_matches(false), + no_size_t_is_usize => |b, _| b.size_t_is_usize(false), + no_rustfmt_bindings => |b, _| b.formatter(Formatter::None), + formatter, + no_partialeq, + no_copy, + no_debug, + no_default, + no_hash, + must_use_type, + dynamic_loading => Builder::dynamic_library_name, + dynamic_link_require_all, + prefix_link_name => |b, prefix| b.parse_callbacks(Box::new(PrefixLinkNameCallback { prefix })), + respect_cxx_access_specs, + translate_enum_integer_types, + c_naming, + explicit_padding, + use_specific_virtual_function_receiver, + use_distinct_char16_t, + represent_cxx_operators, + vtable_generation, + sort_semantically, + merge_extern_blocks, + override_abi => |b, (abi, regex)| b.override_abi(abi, regex), + wrap_unsafe_ops, + clang_macro_fallback => |b, _| b.clang_macro_fallback(), + clang_macro_fallback_build_dir, + flexarray_dst, + wrap_static_fns, + wrap_static_fns_path, + wrap_static_fns_suffix, + default_visibility, + generate_deleted_functions, + generate_pure_virtual_functions, + generate_private_functions, + } + ); + + let mut values = module_raw_line.into_iter(); + while let Some(module) = values.next() { + let line = values.next().unwrap(); + builder = builder.module_raw_line(module, line); + } + + let output = if let Some(path) = &output { + let file = File::create(path)?; + if let Some(depfile) = depfile { + builder = builder.depfile(path, depfile); + } + Box::new(io::BufWriter::new(file)) as Box + } else { + if let Some(depfile) = depfile { + builder = builder.depfile("-", depfile); + } + Box::new(io::BufWriter::new(io::stdout())) as Box + }; + + if dump_preprocessed_input { + builder.dump_preprocessed_input()?; + } + + if let Some(path) = rustfmt_configuration_file { + builder = builder.rustfmt_configuration_file(Some(path)); + } + + for (custom_derives, kind, _name) in [ + (with_derive_custom, None, "--with-derive-custom"), + ( + with_derive_custom_struct, + Some(TypeKind::Struct), + "--with-derive-custom-struct", + ), + ( + with_derive_custom_enum, + Some(TypeKind::Enum), + "--with-derive-custom-enum", + ), + ( + with_derive_custom_union, + Some(TypeKind::Union), + "--with-derive-custom-union", + ), + ] { + #[cfg(feature = "experimental")] + let name = emit_diagnostics.then_some(_name); + + for (derives, regex) in custom_derives { + let mut regex_set = RegexSet::default(); + regex_set.insert(regex); + + #[cfg(feature = "experimental")] + regex_set.build_with_diagnostics(false, name); + #[cfg(not(feature = "experimental"))] + regex_set.build(false); + + builder = builder.parse_callbacks(Box::new(CustomDeriveCallback { + derives, + kind, + regex_set, + })); + } + } + + for (custom_attributes, kind, _name) in [ + (with_attribute_custom, None, "--with-attribute-custom"), + ( + with_attribute_custom_struct, + Some(TypeKind::Struct), + "--with-attribute-custom-struct", + ), + ( + with_attribute_custom_enum, + Some(TypeKind::Enum), + "--with-attribute-custom-enum", + ), + ( + with_attribute_custom_union, + Some(TypeKind::Union), + "--with-attribute-custom-union", + ), + ] { + #[cfg(feature = "experimental")] + let name = emit_diagnostics.then_some(_name); + + for (attributes, regex) in custom_attributes { + let mut regex_set = RegexSet::default(); + regex_set.insert(regex); + + #[cfg(feature = "experimental")] + regex_set.build_with_diagnostics(false, name); + #[cfg(not(feature = "experimental"))] + regex_set.build(false); + + builder = + builder.parse_callbacks(Box::new(CustomAttributeCallback { + attributes, + kind, + regex_set, + })); + } + } + + #[cfg(feature = "experimental")] + if emit_diagnostics { + builder = builder.emit_diagnostics(); + } + + Ok((builder, output, verbose)) +} + +/// Trait for CLI arguments that can be applied to a [`Builder`]. +trait CliArg { + /// The value of this argument. + type Value; + + /// Apply the current argument to the passed [`Builder`]. + fn apply( + self, + builder: Builder, + f: impl Fn(Builder, Self::Value) -> Builder, + ) -> Builder; +} + +/// Boolean arguments are applied when they evaluate to `true`. +impl CliArg for bool { + type Value = bool; + + fn apply( + self, + mut builder: Builder, + f: impl Fn(Builder, Self::Value) -> Builder, + ) -> Builder { + if self { + builder = f(builder, self); + } + + builder + } +} + +/// Optional arguments are applied when they are `Some`. +impl CliArg for Option { + type Value = T; + + fn apply( + self, + mut builder: Builder, + f: impl Fn(Builder, Self::Value) -> Builder, + ) -> Builder { + if let Some(value) = self { + builder = f(builder, value); + } + + builder + } +} + +/// Multiple valued arguments are applied once for each value. +impl CliArg for Vec { + type Value = T; + + fn apply( + self, + mut builder: Builder, + f: impl Fn(Builder, Self::Value) -> Builder, + ) -> Builder { + for value in self { + builder = f(builder, value); + } + + builder + } +} diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/options/mod.rs firefox-140.10.2/third_party/rust/bindgen/options/mod.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/options/mod.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/options/mod.rs Mon May 11 04:49:32 2026 @@ -4,13 +4,15 @@ #[macro_use] mod helpers; mod as_args; +#[cfg(feature = "__cli")] +pub(crate) mod cli; use crate::callbacks::ParseCallbacks; use crate::codegen::{ AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, }; use crate::deps::DepfileSpec; -use crate::features::{RustFeatures, RustTarget}; +use crate::features::{RustEdition, RustFeatures, RustTarget}; use crate::regex_set::RegexSet; use crate::Abi; use crate::Builder; @@ -21,9 +23,7 @@ use crate::DEFAULT_ANON_FIELDS_PREFIX; use std::env; -#[cfg(feature = "experimental")] -use std::path::Path; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::rc::Rc; use as_args::AsArgs; @@ -37,20 +37,20 @@ /// a block of code with the following items: /// /// - `default`: The default value for the field. If this item is omitted, `Default::default()` is -/// used instead, meaning that the type of the field must implement `Default`. +/// used instead, meaning that the type of the field must implement `Default`. /// - `methods`: A block of code containing methods for the `Builder` type. These methods should be -/// related to the field being declared. +/// related to the field being declared. /// - `as_args`: This item declares how the field should be converted into a valid CLI argument for -/// `bindgen` and is used in the [`Builder::command_line_flags`] method which is used to do a -/// roundtrip test of the CLI args in the `bindgen-test` crate. This item can take one of the -/// following: +/// `bindgen` and is used in the [`Builder::command_line_flags`] method which is used to do a +/// roundtrip test of the CLI args in the `bindgen-test` crate. This item can take one of the +/// following: /// - A string literal with the flag if the type of the field implements the [`AsArgs`] trait. /// - A closure with the signature `|field, args: &mut Vec| -> ()` that pushes arguments -/// into the `args` buffer based on the value of the field. This is used if the field does not -/// implement `AsArgs` or if the implementation of the trait is not logically correct for the -/// option and a custom behavior must be taken into account. +/// into the `args` buffer based on the value of the field. This is used if the field does not +/// implement `AsArgs` or if the implementation of the trait is not logically correct for the +/// option and a custom behavior must be taken into account. /// - The `ignore` literal, which does not emit any CLI arguments for this field. This is useful -/// if the field cannot be used from the `bindgen` CLI. +/// if the field cannot be used from the `bindgen` CLI. /// /// As an example, this would be the declaration of a `bool` field called `be_fun` whose default /// value is `false` (the `Default` value for `bool`): @@ -153,6 +153,64 @@ } options! { + /// Whether to specify the type of a virtual function receiver + use_specific_virtual_function_receiver: bool { + methods: { + /// Normally, virtual functions have void* as their 'this' type. + /// If this flag is enabled, override that behavior to indicate a + /// pointer of the specific type. + /// Disabled by default. + pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder { + self.options.use_specific_virtual_function_receiver = doit; + self + } + }, + as_args: "--use-specific-virtual-function-receiver", + }, + + /// Whether we should distinguish between C++'s `char16_t` and `u16`. + /// The C++ type `char16_t` is its own special type; it's not a typedef + /// of some other integer (this differs from C). + /// As standard, bindgen represents C++ `char16_t` as `u16`. + /// Rust does not have a `std::os::raw::c_char16_t` type, and thus + /// we can't use a built-in Rust type in the generated bindings (and + /// nor would it be appropriate as it's a C++-specific type.) + /// But for some uses of bindgen, especially when downstream + /// post-processing occurs, it's important to distinguish `char16_t` + /// from normal `uint16_t`. When this option is enabled, bindgen + /// generates a fake type called `bindgen_cchar16_t`. Downstream + /// code post-processors should arrange to replace this with a + /// real type. + use_distinct_char16_t: bool { + methods: { + /// If this is true, denote `char16_t` as a separate type from `u16`. + /// Disabled by default. + pub fn use_distinct_char16_t(mut self, doit: bool) -> Builder { + self.options.use_distinct_char16_t = doit; + self + } + }, + as_args: "--use-distinct-char16-t", + }, + /// Whether we should output C++ overloaded operators. By itself, + /// this option is not sufficient to produce valid output, because + /// such operators will have names that are not acceptable Rust + /// names (for example `operator=`). If you use this option, you'll also + /// have to rename the resulting functions - for example by using + /// [`ParseCallbacks::generated_name_override`]. + represent_cxx_operators: bool { + methods: { + /// If this is true, output existence of C++ overloaded operators. + /// At present, only operator= is noted. + /// Disabled by default. + pub fn represent_cxx_operators(mut self, doit: bool) -> Builder { + self.options.represent_cxx_operators = doit; + self + } + }, + as_args: "--represent-cxx-operators", + }, + /// Types that have been blocklisted and should not appear anywhere in the generated code. blocklisted_types: RegexSet { methods: { @@ -489,7 +547,7 @@ } } }, - as_args: "--rustified-non-exhaustive-enums", + as_args: "--rustified-non-exhaustive-enum", }, /// `enum`s marked as modules of constants. constified_enum_modules: RegexSet { @@ -508,7 +566,7 @@ constified_enums: RegexSet { methods: { regex_option! { - /// Mark the given `enum` as a set o integer constants. + /// Mark the given `enum` as a set of integer constants. /// /// This is similar to the [`Builder::constified_enum_module`] style, but the /// constants are generated in the current module instead of in a new module. @@ -1143,7 +1201,7 @@ }, as_args: |module_lines, args| { for (module, lines) in module_lines { - for line in lines.iter() { + for line in lines { args.push("--module-raw-line".to_owned()); args.push(module.clone().into()); args.push(line.clone().into()); @@ -1179,6 +1237,35 @@ self.options.input_headers.push(header.into().into_boxed_str()); self } + + /// Add input C/C++ header(s) to generate bindings for. + /// + /// This can be used to generate bindings for a single header: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .headers(["input.h"]) + /// .generate() + /// .unwrap(); + /// ``` + /// + /// Or for multiple headers: + /// + /// ```ignore + /// let bindings = bindgen::Builder::default() + /// .headers(["first.h", "second.h", "third.h"]) + /// .generate() + /// .unwrap(); + /// ``` + pub fn headers(mut self, headers: I) -> Builder + where + I::Item: Into, + { + self.options + .input_headers + .extend(headers.into_iter().map(Into::into).map(Into::into)); + self + } }, // This field is handled specially inside the macro. as_args: ignore, @@ -1205,6 +1292,11 @@ // This field is handled specially inside the macro. as_args: ignore, }, + /// The set of arguments to be passed straight through to Clang for the macro fallback code. + fallback_clang_args: Vec> { + methods: {}, + as_args: ignore, + }, /// Tuples of unsaved file contents of the form (name, contents). input_header_contents: Vec<(Box, Box)> { methods: { @@ -1234,6 +1326,9 @@ parse_callbacks: Vec> { methods: { /// Add a new [`ParseCallbacks`] instance to configure types in different situations. + /// + /// This can also be used with [`CargoCallbacks`](struct@crate::CargoCallbacks) to emit + /// `cargo:rerun-if-changed=...` for all `#include`d header files. pub fn parse_callbacks(mut self, cb: Box) -> Self { self.options.parse_callbacks.push(Rc::from(cb)); self @@ -1389,10 +1484,8 @@ /// Note that they will usually not work. However you can use `-fkeep-inline-functions` /// or `-fno-inline-functions` if you are responsible of compiling the library to make /// them callable. - #[cfg_attr( - feature = "experimental", - doc = "\nCheck the [`Builder::wrap_static_fns`] method for an alternative." - )] + /// + /// Check the [`Builder::wrap_static_fns`] method for an alternative. pub fn generate_inline_functions(mut self, doit: bool) -> Self { self.options.generate_inline_functions = doit; self @@ -1579,9 +1672,26 @@ args.push(rust_target.to_string()); }, }, + /// The Rust edition to use for code generation. + rust_edition: Option { + methods: { + /// Specify the Rust target edition. + /// + /// The default edition is the latest edition supported by the chosen Rust target. + pub fn rust_edition(mut self, rust_edition: RustEdition) -> Self { + self.options.rust_edition = Some(rust_edition); + self + } + } + as_args: |edition, args| { + if let Some(edition) = edition { + args.push("--rust-edition".to_owned()); + args.push(edition.to_string()); + } + }, + }, /// Features to be enabled. They are derived from `rust_target`. rust_features: RustFeatures { - default: RustTarget::default().into(), methods: {}, // This field cannot be set from the CLI, as_args: ignore, @@ -1814,7 +1924,7 @@ }, as_args: "--dynamic-loading", }, - /// Whether to equire successful linkage for all routines in a shared library. + /// Whether to require successful linkage for all routines in a shared library. dynamic_link_require_all: bool { methods: { /// Set whether to require successful linkage for all routines in a shared library. @@ -1879,7 +1989,7 @@ }, as_args: "--c-naming", }, - /// Wether to always emit explicit padding fields. + /// Whether to always emit explicit padding fields. force_explicit_padding: bool { methods: { /// Set whether to always emit explicit padding fields. @@ -1951,7 +2061,20 @@ }, as_args: "--wrap-unsafe-ops", }, - /// Patterns for functions whose ABI should be overriden. + /// Use DSTs to represent structures with flexible array members. + flexarray_dst: bool { + methods: { + /// Use DSTs to represent structures with flexible array members. + /// + /// This option is disabled by default. + pub fn flexarray_dst(mut self, doit: bool) -> Self { + self.options.flexarray_dst = doit; + self + } + }, + as_args: "--flexarray-dst", + }, + /// Patterns for functions whose ABI should be overridden. abi_overrides: HashMap { methods: { regex_option! { @@ -1970,7 +2093,7 @@ for (abi, set) in overrides { for item in set.get_items() { args.push("--override-abi".to_owned()); - args.push(format!("{}={}", item, abi)); + args.push(format!("{item}={abi}")); } } }, @@ -1978,8 +2101,7 @@ /// Whether to generate wrappers for `static` functions. wrap_static_fns: bool { methods: { - #[cfg(feature = "experimental")] - /// Set whether to generate wrappers for `static`` functions. + /// Set whether to generate wrappers for `static` functions. /// /// Passing `true` to this method will generate a C source file with non-`static` /// functions that call the `static` functions found in the input headers and can be @@ -1997,7 +2119,6 @@ /// The suffix to be added to the function wrappers for `static` functions. wrap_static_fns_suffix: Option { methods: { - #[cfg(feature = "experimental")] /// Set the suffix added to the wrappers for `static` functions. /// /// This option only comes into effect if `true` is passed to the @@ -2014,7 +2135,6 @@ /// The path of the file where the wrappers for `static` functions will be emitted. wrap_static_fns_path: Option { methods: { - #[cfg(feature = "experimental")] /// Set the path for the source code file that would be created if any wrapper /// functions must be generated due to the presence of `static` functions. /// @@ -2075,5 +2195,92 @@ } }, as_args: "--emit-diagnostics", + }, + /// Whether to use Clang evaluation on temporary files as a fallback for macros that fail to + /// parse. + clang_macro_fallback: bool { + methods: { + /// Use Clang as a fallback for macros that fail to parse using `CExpr`. + /// + /// This uses a workaround to evaluate each macro in a temporary file. Because this + /// results in slower compilation, this option is opt-in. + pub fn clang_macro_fallback(mut self) -> Self { + self.options.clang_macro_fallback = true; + self + } + }, + as_args: "--clang-macro-fallback", } + /// Path to use for temporary files created by clang macro fallback code like precompiled + /// headers. + clang_macro_fallback_build_dir: Option { + methods: { + /// Set a path to a directory to which `.c` and `.h.pch` files should be written for the + /// purpose of using clang to evaluate macros that can't be easily parsed. + /// + /// The default location for `.h.pch` files is the directory that the corresponding + /// `.h` file is located in. The default for the temporary `.c` file used for clang + /// parsing is the current working directory. Both of these defaults are overridden + /// by this option. + pub fn clang_macro_fallback_build_dir>(mut self, path: P) -> Self { + self.options.clang_macro_fallback_build_dir = Some(path.as_ref().to_owned()); + self + } + }, + as_args: "--clang-macro-fallback-build-dir", + } + /// Whether to always report C++ "deleted" functions. + generate_deleted_functions: bool { + methods: { + /// Set whether to generate C++ functions even marked "=deleted" + /// + /// Although not useful to call these functions, downstream code + /// generators may need to know whether they've been deleted in + /// order to determine the relocatability of a C++ type + /// (specifically by virtue of which constructors exist.) + pub fn generate_deleted_functions(mut self, doit: bool) -> Self { + self.options.generate_deleted_functions = doit; + self + } + + }, + as_args: "--generate-deleted-functions", + }, + /// Whether to always report C++ "pure virtual" functions. + generate_pure_virtual_functions: bool { + methods: { + /// Set whether to generate C++ functions that are pure virtual. + /// + /// These functions can't be called, so the only reason + /// to generate them is if downstream postprocessors + /// need to know of their existence. This is necessary, + /// for instance, to determine whether a type itself is + /// pure virtual and thus can't be allocated. + /// Downstream code generators may choose to make code to + /// allow types to be allocated but need to avoid doing so + /// if the type contains pure virtual functions. + pub fn generate_pure_virtual_functions(mut self, doit: bool) -> Self { + self.options.generate_pure_virtual_functions = doit; + self + } + + }, + as_args: "--generate-pure-virtual-functions", + }, + /// Whether to always report C++ "private" functions. + generate_private_functions: bool { + methods: { + /// Set whether to generate C++ functions that are private. + /// + /// These functions can't be called, so the only reason + /// to generate them is if downstream postprocessors + /// need to know of their existence. + pub fn generate_private_functions(mut self, doit: bool) -> Self { + self.options.generate_private_functions = doit; + self + } + + }, + as_args: "--generate-private-functions", + }, } diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/regex_set.rs firefox-140.10.2/third_party/rust/bindgen/regex_set.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/regex_set.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/regex_set.rs Mon May 11 04:49:32 2026 @@ -6,7 +6,7 @@ /// A dynamic set of regular expressions. #[derive(Clone, Debug, Default)] -pub struct RegexSet { +pub(crate) struct RegexSet { items: Vec>, /// Whether any of the items in the set was ever matched. The length of this /// vector is exactly the length of `items`. @@ -17,18 +17,13 @@ } impl RegexSet { - /// Create a new RegexSet - pub fn new() -> RegexSet { - RegexSet::default() - } - /// Is this set empty? - pub fn is_empty(&self) -> bool { + pub(crate) fn is_empty(&self) -> bool { self.items.is_empty() } /// Insert a new regex into this set. - pub fn insert(&mut self, string: S) + pub(crate) fn insert(&mut self, string: S) where S: AsRef, { @@ -38,13 +33,13 @@ } /// Returns slice of String from its field 'items' - pub fn get_items(&self) -> &[Box] { + pub(crate) fn get_items(&self) -> &[Box] { &self.items } /// Returns an iterator over regexes in the set which didn't match any /// strings yet. - pub fn unmatched_items(&self) -> impl Iterator { + pub(crate) fn unmatched_items(&self) -> impl Iterator { self.items.iter().enumerate().filter_map(move |(i, item)| { if !self.record_matches || self.matched[i].get() { return None; @@ -54,28 +49,29 @@ }) } - /// Construct a RegexSet from the set of entries we've accumulated. + /// Construct a `RegexSet` from the set of entries we've accumulated. /// /// Must be called before calling `matches()`, or it will always return /// false. #[inline] - pub fn build(&mut self, record_matches: bool) { - self.build_inner(record_matches, None) + #[allow(unused)] + pub(crate) fn build(&mut self, record_matches: bool) { + self.build_inner(record_matches, None); } #[cfg(all(feature = "__cli", feature = "experimental"))] - /// Construct a RegexSet from the set of entries we've accumulated and emit diagnostics if the + /// Construct a `RegexSet` from the set of entries we've accumulated and emit diagnostics if the /// name of the regex set is passed to it. /// /// Must be called before calling `matches()`, or it will always return /// false. #[inline] - pub fn build_with_diagnostics( + pub(crate) fn build_with_diagnostics( &mut self, record_matches: bool, name: Option<&'static str>, ) { - self.build_inner(record_matches, name) + self.build_inner(record_matches, name); } #[cfg(all(not(feature = "__cli"), feature = "experimental"))] @@ -90,7 +86,7 @@ record_matches: bool, name: Option<&'static str>, ) { - self.build_inner(record_matches, name) + self.build_inner(record_matches, name); } fn build_inner( @@ -98,12 +94,12 @@ record_matches: bool, _name: Option<&'static str>, ) { - 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), Err(e) => { - warn!("Invalid regex in {:?}: {:?}", self.items, e); + warn!("Invalid regex in {:?}: {e:?}", self.items); #[cfg(feature = "experimental")] if let Some(name) = _name { invalid_regex_warning(self, e, name); @@ -114,14 +110,13 @@ } /// Does the given `string` match any of the regexes in this set? - pub fn matches(&self, string: S) -> bool + pub(crate) fn matches(&self, string: S) -> bool where S: AsRef, { let s = string.as_ref(); - let set = match self.set { - Some(ref set) => set, - None => return false, + let Some(ref set) = self.set else { + return false; }; if !self.record_matches { @@ -132,7 +127,7 @@ if !matches.matched_any() { return false; } - for i in matches.iter() { + for i in &matches { self.matched[i].set(true); } @@ -180,20 +175,20 @@ diagnostic.with_title( "Error while parsing a regular expression.", - Level::Warn, + Level::Warning, ); } else { - diagnostic.with_title(string, Level::Warn); + diagnostic.with_title(string, Level::Warning); } } err => { let err = err.to_string(); - diagnostic.with_title(err, Level::Warn); + diagnostic.with_title(err, Level::Warning); } } diagnostic.add_annotation( - format!("This regular expression was passed via `{}`.", name), + format!("This regular expression was passed via `{name}`."), Level::Note, ); diff -rNu firefox-140.10.2.orig/third_party/rust/bindgen/time.rs firefox-140.10.2/third_party/rust/bindgen/time.rs --- firefox-140.10.2.orig/third_party/rust/bindgen/time.rs Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/bindgen/time.rs Mon May 11 04:49:32 2026 @@ -29,23 +29,23 @@ /// Returns the time elapsed since the timer's creation pub fn elapsed(&self) -> Duration { - Instant::now() - self.start + self.start.elapsed() } fn print_elapsed(&mut self) { if self.output { let elapsed = self.elapsed(); let time = (elapsed.as_secs() as f64) * 1e3 + - (elapsed.subsec_nanos() as f64) / 1e6; + f64::from(elapsed.subsec_nanos()) / 1e6; let stderr = io::stderr(); // Arbitrary output format, subject to change. - writeln!(stderr.lock(), " time: {:>9.3} ms.\t{}", time, self.name) + writeln!(stderr.lock(), " time: {time:>9.3} ms.\t{}", self.name) .expect("timer write should not fail"); } } } -impl<'a> Drop for Timer<'a> { +impl Drop for Timer<'_> { fn drop(&mut self) { self.print_elapsed(); } diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/.cargo-checksum.json firefox-140.10.2/third_party/rust/lazycell/.cargo-checksum.json --- firefox-140.10.2.orig/third_party/rust/lazycell/.cargo-checksum.json Wed May 6 16:54:52 2026 +++ firefox-140.10.2/third_party/rust/lazycell/.cargo-checksum.json Thu Jan 1 01:00:00 1970 @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"54036052985525a153f9e6c9dda6a143b7494a477908fb28f5705f92dd387059","Cargo.toml":"79f5da117603f75361b9a7309f102a9ab70b66d5c1c269a30f66fdea58ccc657","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"03f6ccb4e6040abccf12b31551bbbd1800a5069a17950bbd6db850d85744800f","README.md":"26e4440387d4fc898f377eb5394f3432f8625ed8aa46e02ffb61aac8b2032967","src/lib.rs":"3fcef569bd4feb760925e34aef0e66739a0827cbc1b26ae033f57e322c3a2515","src/serde_impl.rs":"4903fb722748e91bdc4b481c7f3309e79e962f75c9717e7e13edcccd0242a52d"},"package":"830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"} \ No newline at end of file diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/CHANGELOG.md firefox-140.10.2/third_party/rust/lazycell/CHANGELOG.md --- firefox-140.10.2.orig/third_party/rust/lazycell/CHANGELOG.md Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/lazycell/CHANGELOG.md Thu Jan 1 01:00:00 1970 @@ -1,197 +0,0 @@ - -## v1.3.0 (2020-08-12) - - -#### Bug Fixes - -* Add custom `impl Default` to support non-Default-able `` types ([b49f4eab](https://github.com/indiv0/lazycell/commit/b49f4eabec49c0a5146ef01017c2506a3c357180)) -* **lazycell:** Fix unsound aliasing in `LazyCell::fill` ([e789ac1a](https://github.com/indiv0/lazycell/commit/e789ac1a99010ad79c2d09c761fec6d67053647d), closes [#98](https://github.com/indiv0/lazycell/issues/98)) - -#### Features - -* Implement serde support ([e728a0b6](https://github.com/indiv0/lazycell/commit/e728a0b680e607b793a81b5af7bf7f1d2c0eb5e5)) - -#### Documentation - -* fix typo ([5f5ba9d5](https://github.com/indiv0/lazycell/commit/5f5ba9d5ac3364f8376c0c872c2e5094974385ba)) - - - - -## v1.2.1 (2018-12-03) - - -#### Features - -* Implement Clone for LazyCell and AtomicLazyCell ([30fe4a8f](https://github.com/indiv0/lazycell/commit/30fe4a8f568059b3c78ed149a810962a676cb2b2)) - - - - -## v1.2.0 (2018-09-19) - - -#### Features - -* add `LazyCell::replace` for infallible access ([a63ffb90](https://github.com/indiv0/lazycell/commit/a63ffb9040a5e0683a9bbf9d3d5ef589f2ca8b7c)) - - - - -## v1.1.0 (2018-09-10) - - -#### Documentation - -* add note regarding LazyCell::borrow_mut ([9d634d1f](https://github.com/indiv0/lazycell/commit/9d634d1fd9a21b7aa075d407bedf9fe77ba8b79f)) -* describe mutability more consistently ([b8078029](https://github.com/indiv0/lazycell/commit/b80780294611e92efddcdd33a701b3049ab5c5eb), closes [#78](https://github.com/indiv0/lazycell/issues/78)) - -#### Improvements - -* add NONE constant for an empty AtomicLazyCell ([31aff0da](https://github.com/indiv0/lazycell/commit/31aff0dacf824841c5f38ef4acf0aa71ec4c36eb), closes [#87](https://github.com/indiv0/lazycell/issues/87)) -* add `LazyCell::borrow_mut_with` and `LazyCell::try_borrow_mut_with` ([fdc6d268](https://github.com/indiv0/lazycell/commit/fdc6d268f0e9a6668768302f45fe2bb4aa9a7c34), closes [#79](https://github.com/indiv0/lazycell/issues/79), [#80](https://github.com/indiv0/lazycell/issues/80)) - - - - -## v1.0.0 (2018-06-06) - - -#### Features - -* Add #![no_std] ([e59f6b55](https://github.com/indiv0/lazycell/commit/e59f6b5531e310d3df26b0eb40b1431937f38096)) - - - - -## 0.6.0 (2017-11-25) - - -#### Bug Fixes - -* fix soundness hole in borrow_with ([d1f46bef](https://github.com/indiv0/lazycell/commit/d1f46bef9d1397570aa9c3e87e18e0d16e6d1585)) - -#### Features - -* add Default derives ([71bc5088](https://github.com/indiv0/lazycell/commit/71bc50880cd8e20002038197c9b890f5b76ad096)) -* add LazyCell::try_borrow_with ([bffa4028](https://github.com/indiv0/lazycell/commit/bffa402896670b5c78a9ec050d82a58ee98de6fb)) -* add LazyCell::borrow_mut method ([fd419dea](https://github.com/indiv0/lazycell/commit/fd419dea965ff1ad3853f26f37e8d107c6ca096c)) - -#### Breaking Changes - -* add `T: Send` for `AtomicLazyCell` `Sync` impl ([668bb2fa](https://github.com/indiv0/lazycell/commit/668bb2fa974fd6707c4c7edad292c76a9017d74d), closes [#67](https://github.com/indiv0/lazycell/issues/67)) - -#### Improvements - -* add `T: Send` for `AtomicLazyCell` `Sync` impl ([668bb2fa](https://github.com/indiv0/lazycell/commit/668bb2fa974fd6707c4c7edad292c76a9017d74d), closes [#67](https://github.com/indiv0/lazycell/issues/67)) - - - - -## v0.5.1 (2017-03-24) - - -#### Documentation - -* fix missing backticks ([44bafaaf](https://github.com/indiv0/lazycell/commit/44bafaaf93a91641261f58ee38adadcd4af6458e)) - -#### Improvements - -* derive `Debug` impls ([9da0a5a2](https://github.com/indiv0/lazycell/commit/9da0a5a2ffac1fef03ef02851c2c89d26d67d225)) - -#### Features - -* Add get method for Copy types ([dc8f8209](https://github.com/indiv0/lazycell/commit/dc8f8209888b6eba6d18717eba6a22614629b997)) - - - - -## v0.5.0 (2016-12-08) - - -#### Features - -* add borrow_with to LazyCell ([a15efa35](https://github.com/indiv0/lazycell/commit/a15efa359ea5a31a66ba57fc5b25f90c87b4b0dd)) - - - - -## (2016-08-17) - - -#### Breaking Changes - -* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/)) - -#### Improvements - -* **LazyCell:** return Err(value) on full cell ([68f3415d](https://github.com/indiv0/lazycell/commit/68f3415dd5d6a66ba047a133b7028ebe4f1c5070), breaks [#](https://github.com/indiv0/lazycell/issues/)) - - - - -## (2016-08-16) - - -#### Features - -* add AtomicLazyCell which is thread-safe ([85afbd36](https://github.com/indiv0/lazycell/commit/85afbd36d8a148e14cc53654b39ddb523980124d)) - -#### Improvements - -* Use UnsafeCell instead of RefCell ([3347a8e9](https://github.com/indiv0/lazycell/commit/3347a8e97d2215a47e25c1e2fc953e8052ad8eb6)) - - - - -## (2016-04-18) - - -#### Documentation - -* put types in between backticks ([607cf939](https://github.com/indiv0/lazycell/commit/607cf939b05e35001ba3070ec7a0b17b064e7be1)) - - - - -## v0.2.0 (2016-03-28) - - -#### Features - -* **lazycell:** - * add tests for `LazyCell` struct ([38f1313d](https://github.com/indiv0/lazycell/commit/38f1313d98542ca8c98b424edfa9ba9c3975f99e), closes [#30](https://github.com/indiv0/lazycell/issues/30)) - * remove unnecessary `Default` impl ([68c16d2d](https://github.com/indiv0/lazycell/commit/68c16d2df4e9d13d5298162c06edf918246fd758)) - -#### Documentation - -* **CHANGELOG:** removed unnecessary sections ([1cc0555d](https://github.com/indiv0/lazycell/commit/1cc0555d875898a01b0832ff967aed6b40e720eb)) -* **README:** add link to documentation ([c8dc33f0](https://github.com/indiv0/lazycell/commit/c8dc33f01f2c0dc187f59ee53a2b73081053012b), closes [#13](https://github.com/indiv0/lazycell/issues/13)) - - - - -## v0.1.0 (2016-03-16) - - -#### Features - -* **lib.rs:** implement Default trait for LazyCell ([150a6304](https://github.com/indiv0/LazyCell/commit/150a6304a230ee1de8424e49c447ec1b2d6578ce)) - - - - -## v0.0.1 (2016-03-16) - - -#### Bug Fixes - -* **Cargo.toml:** loosen restrictions on Clippy version ([84dd8f96](https://github.com/indiv0/LazyCell/commit/84dd8f960000294f9dad47d776a41b98ed812981)) - -#### Features - -* add initial implementation ([4b39764a](https://github.com/indiv0/LazyCell/commit/4b39764a575bcb701dbd8047b966f72720fd18a4)) -* add initial commit ([a80407a9](https://github.com/indiv0/LazyCell/commit/a80407a907ef7c9401f120104663172f6965521a)) - - - diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/Cargo.toml firefox-140.10.2/third_party/rust/lazycell/Cargo.toml --- firefox-140.10.2.orig/third_party/rust/lazycell/Cargo.toml Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/lazycell/Cargo.toml Thu Jan 1 01:00:00 1970 @@ -1,34 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "lazycell" -version = "1.3.0" -authors = ["Alex Crichton ", "Nikita Pekin "] -include = ["CHANGELOG.md", "Cargo.toml", "LICENSE-MIT", "LICENSE-APACHE", "README.md", "src/**/*.rs"] -description = "A library providing a lazily filled Cell struct" -documentation = "http://indiv0.github.io/lazycell/lazycell/" -readme = "README.md" -keywords = ["lazycell", "lazy", "cell", "library"] -license = "MIT/Apache-2.0" -repository = "https://github.com/indiv0/lazycell" -[dependencies.clippy] -version = "0.0" -optional = true - -[dependencies.serde] -version = "^1" -optional = true - -[features] -nightly = [] -nightly-testing = ["clippy", "nightly"] diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/LICENSE-APACHE firefox-140.10.2/third_party/rust/lazycell/LICENSE-APACHE --- firefox-140.10.2.orig/third_party/rust/lazycell/LICENSE-APACHE Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/lazycell/LICENSE-APACHE Thu Jan 1 01:00:00 1970 @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/LICENSE-MIT firefox-140.10.2/third_party/rust/lazycell/LICENSE-MIT --- firefox-140.10.2.orig/third_party/rust/lazycell/LICENSE-MIT Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/lazycell/LICENSE-MIT Thu Jan 1 01:00:00 1970 @@ -1,26 +0,0 @@ -Original work Copyright (c) 2014 The Rust Project Developers -Modified work Copyright (c) 2016-2018 Nikita Pekin and lazycell contributors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/README.md firefox-140.10.2/third_party/rust/lazycell/README.md --- firefox-140.10.2.orig/third_party/rust/lazycell/README.md Wed May 6 16:54:53 2026 +++ firefox-140.10.2/third_party/rust/lazycell/README.md Thu Jan 1 01:00:00 1970 @@ -1,73 +0,0 @@ -# lazycell - - - - - - - - - -
Linuxtravis-badge
- cargo-downloads-badge - api-docs-badge - crates-io - license-badge - coveralls-badge -
- -Rust library providing a lazily filled Cell. - -# Table of Contents - -* [Usage](#usage) -* [Contributing](#contributing) -* [Credits](#credits) -* [License](#license) - -## Usage - -Add the following to your `Cargo.toml`: - -```toml -[dependencies] -lazycell = "1.3" -``` - -And in your `lib.rs` or `main.rs`: - -```rust -extern crate lazycell; -``` - -See the [API docs][api-docs] for information on using the crate in your library. - -## Contributing - -Contributions are always welcome! -If you have an idea for something to add (code, documentation, tests, examples, -etc.) feel free to give it a shot. - -Please read [CONTRIBUTING.md][contributing] before you start contributing. - -## Credits - -The LazyCell library is based originally on work by The Rust Project Developers -for the project [crates.io][crates-io-repo]. - -The list of contributors to this project can be found at -[CONTRIBUTORS.md][contributors]. - -## License - -LazyCell is distributed under the terms of both the MIT license and the Apache -License (Version 2.0). - -See [LICENSE-APACHE][license-apache], and [LICENSE-MIT][license-mit] for details. - -[api-docs]: https://indiv0.github.io/lazycell/lazycell -[contributing]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTING.md "Contribution Guide" -[contributors]: https://github.com/indiv0/lazycell/blob/master/CONTRIBUTORS.md "List of Contributors" -[crates-io-repo]: https://github.com/rust-lang/crates.io "rust-lang/crates.io: Source code for crates.io" -[license-apache]: https://github.com/indiv0/lazycell/blob/master/LICENSE-APACHE "Apache-2.0 License" -[license-mit]: https://github.com/indiv0/lazycell/blob/master/LICENSE-MIT "MIT License" diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/src/lib.rs firefox-140.10.2/third_party/rust/lazycell/src/lib.rs --- firefox-140.10.2.orig/third_party/rust/lazycell/src/lib.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/lazycell/src/lib.rs Thu Jan 1 01:00:00 1970 @@ -1,680 +0,0 @@ -// Original work Copyright (c) 2014 The Rust Project Developers -// Modified work Copyright (c) 2016-2020 Nikita Pekin and the lazycell contributors -// See the README.md file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![cfg_attr(not(test), no_std)] - -#![deny(missing_docs)] -#![cfg_attr(feature = "nightly", feature(plugin))] -#![cfg_attr(feature = "clippy", plugin(clippy))] - -//! This crate provides a `LazyCell` struct which acts as a lazily filled -//! `Cell`. -//! -//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of -//! the entire object, but only of the borrows returned. A `LazyCell` is a -//! variation on `RefCell` which allows borrows to be tied to the lifetime of -//! the outer object. -//! -//! # Example -//! -//! The following example shows a quick example of the basic functionality of -//! `LazyCell`. -//! -//! ``` -//! use lazycell::LazyCell; -//! -//! let lazycell = LazyCell::new(); -//! -//! assert_eq!(lazycell.borrow(), None); -//! assert!(!lazycell.filled()); -//! lazycell.fill(1).ok(); -//! assert!(lazycell.filled()); -//! assert_eq!(lazycell.borrow(), Some(&1)); -//! assert_eq!(lazycell.into_inner(), Some(1)); -//! ``` -//! -//! `AtomicLazyCell` is a variant that uses an atomic variable to manage -//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell` -//! is that after it is initialized, it can't be modified. - - -#[cfg(not(test))] -#[macro_use] -extern crate core as std; -#[cfg(feature = "serde")] -extern crate serde; - -#[cfg(feature = "serde")] -mod serde_impl; - -use std::cell::UnsafeCell; -use std::mem; -use std::sync::atomic::{AtomicUsize, Ordering}; - -/// A lazily filled `Cell`, with mutable contents. -/// -/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut` -/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the -/// contents. -#[derive(Debug)] -pub struct LazyCell { - inner: UnsafeCell>, -} - -impl LazyCell { - /// Creates a new, empty, `LazyCell`. - pub fn new() -> LazyCell { - LazyCell { inner: UnsafeCell::new(None) } - } - - /// Put a value into this cell. - /// - /// This function will return `Err(value)` if the cell is already full. - pub fn fill(&self, value: T) -> Result<(), T> { - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); - } - let slot = unsafe { &mut *self.inner.get() }; - *slot = Some(value); - - Ok(()) - } - - /// Put a value into this cell. - /// - /// Note that this function is infallible but requires `&mut self`. By - /// requiring `&mut self` we're guaranteed that no active borrows to this - /// cell can exist so we can always fill in the value. This may not always - /// be usable, however, as `&mut self` may not be possible to borrow. - /// - /// # Return value - /// - /// This function returns the previous value, if any. - pub fn replace(&mut self, value: T) -> Option { - mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) - } - - /// Test whether this cell has been previously filled. - pub fn filled(&self) -> bool { - self.borrow().is_some() - } - - /// Borrows the contents of this lazy cell for the duration of the cell - /// itself. - /// - /// This function will return `Some` if the cell has been previously - /// initialized, and `None` if it has not yet been initialized. - pub fn borrow(&self) -> Option<&T> { - unsafe { &*self.inner.get() }.as_ref() - } - - /// Borrows the contents of this lazy cell mutably for the duration of the cell - /// itself. - /// - /// This function will return `Some` if the cell has been previously - /// initialized, and `None` if it has not yet been initialized. - pub fn borrow_mut(&mut self) -> Option<&mut T> { - unsafe { &mut *self.inner.get() }.as_mut() - } - - /// Borrows the contents of this lazy cell for the duration of the cell - /// itself. - /// - /// If the cell has not yet been filled, the cell is first filled using the - /// function provided. - /// - /// # Panics - /// - /// Panics if the cell becomes filled as a side effect of `f`. - pub fn borrow_with T>(&self, f: F) -> &T { - if let Some(value) = self.borrow() { - return value; - } - let value = f(); - if self.fill(value).is_err() { - panic!("borrow_with: cell was filled by closure") - } - self.borrow().unwrap() - } - - /// Borrows the contents of this `LazyCell` mutably for the duration of the - /// cell itself. - /// - /// If the cell has not yet been filled, the cell is first filled using the - /// function provided. - /// - /// # Panics - /// - /// Panics if the cell becomes filled as a side effect of `f`. - pub fn borrow_mut_with T>(&mut self, f: F) -> &mut T { - if !self.filled() { - let value = f(); - if self.fill(value).is_err() { - panic!("borrow_mut_with: cell was filled by closure") - } - } - - self.borrow_mut().unwrap() - } - - /// Same as `borrow_with`, but allows the initializing function to fail. - /// - /// # Panics - /// - /// Panics if the cell becomes filled as a side effect of `f`. - pub fn try_borrow_with(&self, f: F) -> Result<&T, E> - where F: FnOnce() -> Result - { - if let Some(value) = self.borrow() { - return Ok(value); - } - let value = f()?; - if self.fill(value).is_err() { - panic!("try_borrow_with: cell was filled by closure") - } - Ok(self.borrow().unwrap()) - } - - /// Same as `borrow_mut_with`, but allows the initializing function to fail. - /// - /// # Panics - /// - /// Panics if the cell becomes filled as a side effect of `f`. - pub fn try_borrow_mut_with(&mut self, f: F) -> Result<&mut T, E> - where F: FnOnce() -> Result - { - if self.filled() { - return Ok(self.borrow_mut().unwrap()); - } - let value = f()?; - if self.fill(value).is_err() { - panic!("try_borrow_mut_with: cell was filled by closure") - } - Ok(self.borrow_mut().unwrap()) - } - - /// Consumes this `LazyCell`, returning the underlying value. - pub fn into_inner(self) -> Option { - // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe - // function. This unsafe can be removed when supporting Rust older than - // 1.25 is not needed. - #[allow(unused_unsafe)] - unsafe { self.inner.into_inner() } - } -} - -impl LazyCell { - /// Returns a copy of the contents of the lazy cell. - /// - /// This function will return `Some` if the cell has been previously initialized, - /// and `None` if it has not yet been initialized. - pub fn get(&self) -> Option { - unsafe { *self.inner.get() } - } -} - -impl Default for LazyCell { - fn default() -> Self { - Self::new() - } -} - -impl Clone for LazyCell { - /// Create a clone of this `LazyCell` - /// - /// If self has not been initialized, returns an uninitialized `LazyCell` - /// otherwise returns a `LazyCell` already initialized with a clone of the - /// contents of self. - fn clone(&self) -> LazyCell { - LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) } - } -} - -// Tracks the AtomicLazyCell inner state -const NONE: usize = 0; -const LOCK: usize = 1; -const SOME: usize = 2; - -/// A lazily filled and thread-safe `Cell`, with frozen contents. -#[derive(Debug)] -pub struct AtomicLazyCell { - inner: UnsafeCell>, - state: AtomicUsize, -} - -impl AtomicLazyCell { - /// An empty `AtomicLazyCell`. - pub const NONE: Self = Self { - inner: UnsafeCell::new(None), - state: AtomicUsize::new(NONE), - }; - - /// Creates a new, empty, `AtomicLazyCell`. - pub fn new() -> AtomicLazyCell { - Self::NONE - } - - /// Put a value into this cell. - /// - /// This function will return `Err(value)` if the cell is already full. - pub fn fill(&self, t: T) -> Result<(), T> { - if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) { - return Err(t); - } - - unsafe { *self.inner.get() = Some(t) }; - - if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) { - panic!("unable to release lock"); - } - - Ok(()) - } - - /// Put a value into this cell. - /// - /// Note that this function is infallible but requires `&mut self`. By - /// requiring `&mut self` we're guaranteed that no active borrows to this - /// cell can exist so we can always fill in the value. This may not always - /// be usable, however, as `&mut self` may not be possible to borrow. - /// - /// # Return value - /// - /// This function returns the previous value, if any. - pub fn replace(&mut self, value: T) -> Option { - match mem::replace(self.state.get_mut(), SOME) { - NONE | SOME => {} - _ => panic!("cell in inconsistent state"), - } - mem::replace(unsafe { &mut *self.inner.get() }, Some(value)) - } - - /// Test whether this cell has been previously filled. - pub fn filled(&self) -> bool { - self.state.load(Ordering::Acquire) == SOME - } - - /// Borrows the contents of this lazy cell for the duration of the cell - /// itself. - /// - /// This function will return `Some` if the cell has been previously - /// initialized, and `None` if it has not yet been initialized. - pub fn borrow(&self) -> Option<&T> { - match self.state.load(Ordering::Acquire) { - SOME => unsafe { &*self.inner.get() }.as_ref(), - _ => None, - } - } - - /// Consumes this `LazyCell`, returning the underlying value. - pub fn into_inner(self) -> Option { - // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe - // function. This unsafe can be removed when supporting Rust older than - // 1.25 is not needed. - #[allow(unused_unsafe)] - unsafe { self.inner.into_inner() } - } -} - -impl AtomicLazyCell { - /// Returns a copy of the contents of the lazy cell. - /// - /// This function will return `Some` if the cell has been previously initialized, - /// and `None` if it has not yet been initialized. - pub fn get(&self) -> Option { - match self.state.load(Ordering::Acquire) { - SOME => unsafe { *self.inner.get() }, - _ => None, - } - } -} - -impl Default for AtomicLazyCell { - fn default() -> Self { - Self::new() - } -} - -impl Clone for AtomicLazyCell { - /// Create a clone of this `AtomicLazyCell` - /// - /// If self has not been initialized, returns an uninitialized `AtomicLazyCell` - /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the - /// contents of self. - fn clone(&self) -> AtomicLazyCell { - self.borrow().map_or( - Self::NONE, - |v| AtomicLazyCell { - inner: UnsafeCell::new(Some(v.clone())), - state: AtomicUsize::new(SOME), - } - ) - } -} - -unsafe impl Sync for AtomicLazyCell {} - -unsafe impl Send for AtomicLazyCell {} - -#[cfg(test)] -mod tests { - use super::{AtomicLazyCell, LazyCell}; - - #[test] - fn test_borrow_from_empty() { - let lazycell: LazyCell = LazyCell::new(); - - let value = lazycell.borrow(); - assert_eq!(value, None); - - let value = lazycell.get(); - assert_eq!(value, None); - } - - #[test] - fn test_fill_and_borrow() { - let lazycell = LazyCell::new(); - - assert!(!lazycell.filled()); - lazycell.fill(1).unwrap(); - assert!(lazycell.filled()); - - let value = lazycell.borrow(); - assert_eq!(value, Some(&1)); - - let value = lazycell.get(); - assert_eq!(value, Some(1)); - } - - #[test] - fn test_borrow_mut() { - let mut lazycell = LazyCell::new(); - assert!(lazycell.borrow_mut().is_none()); - - lazycell.fill(1).unwrap(); - assert_eq!(lazycell.borrow_mut(), Some(&mut 1)); - - *lazycell.borrow_mut().unwrap() = 2; - assert_eq!(lazycell.borrow_mut(), Some(&mut 2)); - - // official way to reset the cell - lazycell = LazyCell::new(); - assert!(lazycell.borrow_mut().is_none()); - } - - #[test] - fn test_already_filled_error() { - let lazycell = LazyCell::new(); - - lazycell.fill(1).unwrap(); - assert_eq!(lazycell.fill(1), Err(1)); - } - - #[test] - fn test_borrow_with() { - let lazycell = LazyCell::new(); - - let value = lazycell.borrow_with(|| 1); - assert_eq!(&1, value); - } - - #[test] - fn test_borrow_with_already_filled() { - let lazycell = LazyCell::new(); - lazycell.fill(1).unwrap(); - - let value = lazycell.borrow_with(|| 1); - assert_eq!(&1, value); - } - - #[test] - fn test_borrow_with_not_called_when_filled() { - let lazycell = LazyCell::new(); - - lazycell.fill(1).unwrap(); - - let value = lazycell.borrow_with(|| 2); - assert_eq!(&1, value); - } - - #[test] - #[should_panic] - fn test_borrow_with_sound_with_reentrancy() { - // Kudos to dbaupp for discovering this issue - // https://www.reddit.com/r/rust/comments/5vs9rt/lazycell_a_rust_library_providing_a_lazilyfilled/de527xm/ - let lazycell: LazyCell> = LazyCell::new(); - - let mut reference: Option<&i32> = None; - - lazycell.borrow_with(|| { - let _ = lazycell.fill(Box::new(1)); - reference = lazycell.borrow().map(|r| &**r); - Box::new(2) - }); - } - - #[test] - fn test_borrow_mut_with() { - let mut lazycell = LazyCell::new(); - - { - let value = lazycell.borrow_mut_with(|| 1); - assert_eq!(&mut 1, value); - *value = 2; - } - assert_eq!(&2, lazycell.borrow().unwrap()); - } - - #[test] - fn test_borrow_mut_with_already_filled() { - let mut lazycell = LazyCell::new(); - lazycell.fill(1).unwrap(); - - let value = lazycell.borrow_mut_with(|| 1); - assert_eq!(&1, value); - } - - #[test] - fn test_borrow_mut_with_not_called_when_filled() { - let mut lazycell = LazyCell::new(); - - lazycell.fill(1).unwrap(); - - let value = lazycell.borrow_mut_with(|| 2); - assert_eq!(&1, value); - } - - #[test] - fn test_try_borrow_with_ok() { - let lazycell = LazyCell::new(); - let result = lazycell.try_borrow_with::<(), _>(|| Ok(1)); - assert_eq!(result, Ok(&1)); - } - - #[test] - fn test_try_borrow_with_err() { - let lazycell = LazyCell::<()>::new(); - let result = lazycell.try_borrow_with(|| Err(1)); - assert_eq!(result, Err(1)); - } - - #[test] - fn test_try_borrow_with_already_filled() { - let lazycell = LazyCell::new(); - lazycell.fill(1).unwrap(); - let result = lazycell.try_borrow_with::<(), _>(|| unreachable!()); - assert_eq!(result, Ok(&1)); - } - - #[test] - #[should_panic] - fn test_try_borrow_with_sound_with_reentrancy() { - let lazycell: LazyCell> = LazyCell::new(); - - let mut reference: Option<&i32> = None; - - let _ = lazycell.try_borrow_with::<(), _>(|| { - let _ = lazycell.fill(Box::new(1)); - reference = lazycell.borrow().map(|r| &**r); - Ok(Box::new(2)) - }); - } - - #[test] - fn test_try_borrow_mut_with_ok() { - let mut lazycell = LazyCell::new(); - { - let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1)); - assert_eq!(result, Ok(&mut 1)); - *result.unwrap() = 2; - } - assert_eq!(&mut 2, lazycell.borrow().unwrap()); - } - - #[test] - fn test_try_borrow_mut_with_err() { - let mut lazycell = LazyCell::<()>::new(); - let result = lazycell.try_borrow_mut_with(|| Err(1)); - assert_eq!(result, Err(1)); - } - - #[test] - fn test_try_borrow_mut_with_already_filled() { - let mut lazycell = LazyCell::new(); - lazycell.fill(1).unwrap(); - let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!()); - assert_eq!(result, Ok(&mut 1)); - } - - #[test] - fn test_into_inner() { - let lazycell = LazyCell::new(); - - lazycell.fill(1).unwrap(); - let value = lazycell.into_inner(); - assert_eq!(value, Some(1)); - } - - #[test] - fn test_atomic_borrow_from_empty() { - let lazycell: AtomicLazyCell = AtomicLazyCell::new(); - - let value = lazycell.borrow(); - assert_eq!(value, None); - - let value = lazycell.get(); - assert_eq!(value, None); - } - - #[test] - fn test_atomic_fill_and_borrow() { - let lazycell = AtomicLazyCell::new(); - - assert!(!lazycell.filled()); - lazycell.fill(1).unwrap(); - assert!(lazycell.filled()); - - let value = lazycell.borrow(); - assert_eq!(value, Some(&1)); - - let value = lazycell.get(); - assert_eq!(value, Some(1)); - } - - #[test] - fn test_atomic_already_filled_panic() { - let lazycell = AtomicLazyCell::new(); - - lazycell.fill(1).unwrap(); - assert_eq!(1, lazycell.fill(1).unwrap_err()); - } - - #[test] - fn test_atomic_into_inner() { - let lazycell = AtomicLazyCell::new(); - - lazycell.fill(1).unwrap(); - let value = lazycell.into_inner(); - assert_eq!(value, Some(1)); - } - - #[test] - fn normal_replace() { - let mut cell = LazyCell::new(); - assert_eq!(cell.fill(1), Ok(())); - assert_eq!(cell.replace(2), Some(1)); - assert_eq!(cell.replace(3), Some(2)); - assert_eq!(cell.borrow(), Some(&3)); - - let mut cell = LazyCell::new(); - assert_eq!(cell.replace(2), None); - } - - #[test] - fn atomic_replace() { - let mut cell = AtomicLazyCell::new(); - assert_eq!(cell.fill(1), Ok(())); - assert_eq!(cell.replace(2), Some(1)); - assert_eq!(cell.replace(3), Some(2)); - assert_eq!(cell.borrow(), Some(&3)); - } - - #[test] - fn clone() { - let mut cell = LazyCell::new(); - let clone1 = cell.clone(); - assert_eq!(clone1.borrow(), None); - assert_eq!(cell.fill(1), Ok(())); - let mut clone2 = cell.clone(); - assert_eq!(clone1.borrow(), None); - assert_eq!(clone2.borrow(), Some(&1)); - assert_eq!(cell.replace(2), Some(1)); - assert_eq!(clone1.borrow(), None); - assert_eq!(clone2.borrow(), Some(&1)); - assert_eq!(clone1.fill(3), Ok(())); - assert_eq!(clone2.replace(4), Some(1)); - assert_eq!(clone1.borrow(), Some(&3)); - assert_eq!(clone2.borrow(), Some(&4)); - assert_eq!(cell.borrow(), Some(&2)); - } - - #[test] - fn clone_atomic() { - let mut cell = AtomicLazyCell::new(); - let clone1 = cell.clone(); - assert_eq!(clone1.borrow(), None); - assert_eq!(cell.fill(1), Ok(())); - let mut clone2 = cell.clone(); - assert_eq!(clone1.borrow(), None); - assert_eq!(clone2.borrow(), Some(&1)); - assert_eq!(cell.replace(2), Some(1)); - assert_eq!(clone1.borrow(), None); - assert_eq!(clone2.borrow(), Some(&1)); - assert_eq!(clone1.fill(3), Ok(())); - assert_eq!(clone2.replace(4), Some(1)); - assert_eq!(clone1.borrow(), Some(&3)); - assert_eq!(clone2.borrow(), Some(&4)); - assert_eq!(cell.borrow(), Some(&2)); - } - - #[test] - fn default() { - #[derive(Default)] - struct Defaultable; - struct NonDefaultable; - - let _: LazyCell = LazyCell::default(); - let _: LazyCell = LazyCell::default(); - - let _: AtomicLazyCell = AtomicLazyCell::default(); - let _: AtomicLazyCell = AtomicLazyCell::default(); - } -} diff -rNu firefox-140.10.2.orig/third_party/rust/lazycell/src/serde_impl.rs firefox-140.10.2/third_party/rust/lazycell/src/serde_impl.rs --- firefox-140.10.2.orig/third_party/rust/lazycell/src/serde_impl.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/lazycell/src/serde_impl.rs Thu Jan 1 01:00:00 1970 @@ -1,86 +0,0 @@ -// Copyright (c) 2020 Nikita Pekin and the lazycell contributors -// See the README.md file at the top-level directory of this distribution. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms.use serde::ser::{Serialize, Serializer}; -use serde::ser::{Serialize, Serializer}; -use serde::de::{self, Deserialize, Deserializer, Visitor}; - -use std::fmt; -use std::marker::PhantomData; - -use super::{LazyCell, AtomicLazyCell}; - -impl Serialize for LazyCell { - fn serialize(&self, serializer: S) -> Result { - match self.borrow() { - Some(val) => serializer.serialize_some(val), - None => serializer.serialize_none() - } - } -} - - -impl Serialize for AtomicLazyCell { - fn serialize(&self, serializer: S) -> Result { - match self.borrow() { - Some(val) => serializer.serialize_some(val), - None => serializer.serialize_none() - } - } -} - -struct LazyCellVisitor(PhantomData<*const T>); -impl<'de, T: Deserialize<'de>> Visitor<'de> for LazyCellVisitor { - type Value = LazyCell; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a LazyCell") - } - - fn visit_some>(self, deserializer: D) -> Result { - let mut cell = LazyCell::new(); - cell.replace(T::deserialize(deserializer)?); - Ok(cell) - } - - fn visit_none(self) -> Result { - Ok(LazyCell::new()) - } -} - -impl<'de, T: Deserialize<'de>> Deserialize<'de> for LazyCell { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_option(LazyCellVisitor(PhantomData)) - } -} - - -struct AtomicLazyCellVisitor(PhantomData<*const T>); -impl<'de, T: Deserialize<'de>> Visitor<'de> for AtomicLazyCellVisitor { - type Value = AtomicLazyCell; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("an AtomicLazyCell") - } - - fn visit_some>(self, deserializer: D) -> Result { - let mut cell = AtomicLazyCell::new(); - cell.replace(T::deserialize(deserializer)?); - Ok(cell) - } - - fn visit_none(self) -> Result { - Ok(AtomicLazyCell::new()) - } -} - - -impl<'de, T: Deserialize<'de>> Deserialize<'de> for AtomicLazyCell { - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_option(AtomicLazyCellVisitor(PhantomData)) - } -} diff -rNu firefox-140.10.2.orig/third_party/rust/neqo-crypto/src/agent.rs firefox-140.10.2/third_party/rust/neqo-crypto/src/agent.rs --- firefox-140.10.2.orig/third_party/rust/neqo-crypto/src/agent.rs Wed May 6 16:54:54 2026 +++ firefox-140.10.2/third_party/rust/neqo-crypto/src/agent.rs Mon May 11 04:49:32 2026 @@ -1089,7 +1089,7 @@ return Err(Error::CertificateLoading); }; secstatus_to_res(unsafe { - ssl::SSL_ConfigServerCert(agent.fd, *cert, *key, null(), 0) + ssl::SSL_ConfigServerCert(agent.fd, (*cert).cast(), (*key).cast(), null(), 0) })?; } diff -rNu firefox-140.10.2.orig/toolkit/crashreporter/client/app/src/ui/macos/mod.rs firefox-140.10.2/toolkit/crashreporter/client/app/src/ui/macos/mod.rs --- firefox-140.10.2.orig/toolkit/crashreporter/client/app/src/ui/macos/mod.rs Wed May 6 16:54:55 2026 +++ firefox-140.10.2/toolkit/crashreporter/client/app/src/ui/macos/mod.rs Mon May 11 04:49:32 2026 @@ -170,7 +170,7 @@ cocoa::NSArray(>::arrayWithObjects_count_( - objects.as_slice().as_ptr() as *const *mut u64, + objects.as_slice().as_ptr() as *const *mut _, objects .as_slice() .len() @@ -1082,8 +1082,8 @@ cocoa::NSAttributedStringKey, cocoa::id, >>::dictionaryWithObject_forKey_( - cocoa::NSColor::placeholderTextColor().0 as u64, - cocoa::NSForegroundColorAttributeName.0 as u64, + std::mem::transmute(cocoa::NSColor::placeholderTextColor().0), + std::mem::transmute(cocoa::NSForegroundColorAttributeName.0), ), ); let string = StrongRef::new(cocoa::NSAttributedString( diff -rNu firefox-140.10.2.orig/tools/profiler/rust-api/build.rs firefox-140.10.2/tools/profiler/rust-api/build.rs --- firefox-140.10.2.orig/tools/profiler/rust-api/build.rs Wed May 6 16:54:55 2026 +++ firefox-140.10.2/tools/profiler/rust-api/build.rs Mon May 11 04:49:32 2026 @@ -88,6 +88,11 @@ // successfully. Otherwise, it fails to build because MarkerSchema has // some std::strings as its fields. .opaque_type("std::string") + .opaque_type("std::unique_ptr") + .opaque_type("mozilla::Maybe") + .opaque_type("mozilla::MallocAllocPolicy") + .opaque_type("mozilla::Variant") + .opaque_type("mozilla::baseprofiler::UniqueJSONStrings") // std::vector needs to be converted to an opaque type because, if it's // not an opaque type, bindgen can't find its size properly and // MarkerSchema's total size reduces. That causes a heap buffer overflow.