Snap for 8249732 from 9462220143e9a759de1a3e30f6c2f92e5d42d4bf to tm-release

Change-Id: I4ceb768e2ea0addf99ef31c836c1e659e84a3517
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 7298dd9..f1c8552 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "9a9438f3d6a3523c69d7bc890e8608b63dbe38a5"
+    "sha1": "89032649044d875983a851fff6fbde2d4e2ceaeb"
   }
 }
diff --git a/Android.bp b/Android.bp
index 3696cbb..9166c33 100644
--- a/Android.bp
+++ b/Android.bp
@@ -46,7 +46,7 @@
     // has rustc warnings
     crate_name: "bindgen",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.59.1",
+    cargo_pkg_version: "0.59.2",
     srcs: [
         "src/main.rs",
         ":copy_bindgen_build_out",
@@ -82,7 +82,7 @@
     // has rustc warnings
     crate_name: "bindgen",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.59.1",
+    cargo_pkg_version: "0.59.2",
     srcs: [
         "src/lib.rs",
         ":copy_bindgen_build_out",
diff --git a/Cargo.lock b/Cargo.lock
index 0e93f41..d79a408 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,7 +33,7 @@
 
 [[package]]
 name = "bindgen"
-version = "0.59.1"
+version = "0.59.2"
 dependencies = [
  "bitflags",
  "cexpr",
@@ -61,43 +61,25 @@
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
 [[package]]
-name = "bitvec"
-version = "0.19.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321"
-dependencies = [
- "funty",
- "radium",
- "tap",
- "wyz",
-]
-
-[[package]]
 name = "cexpr"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
 dependencies = [
  "nom",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-
-[[package]]
-name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "clang-sys"
-version = "1.0.3"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0659001ab56b791be01d4b729c44376edc6718cf389a502e579b77b758f3296c"
+checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c"
 dependencies = [
  "glob",
  "libc",
@@ -126,10 +108,16 @@
 checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
 
 [[package]]
-name = "env_logger"
-version = "0.8.1"
+name = "either"
+version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "env_logger"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
 dependencies = [
  "atty",
  "humantime",
@@ -139,18 +127,12 @@
 ]
 
 [[package]]
-name = "funty"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
-
-[[package]]
 name = "getrandom"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
 dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
  "libc",
  "wasi",
 ]
@@ -163,18 +145,18 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.1.17"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "humantime"
-version = "2.0.1"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "lazy_static"
@@ -190,27 +172,27 @@
 
 [[package]]
 name = "libc"
-version = "0.2.80"
+version = "0.2.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
 
 [[package]]
 name = "libloading"
-version = "0.6.5"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0"
+checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a"
 dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
  "winapi",
 ]
 
 [[package]]
 name = "log"
-version = "0.4.11"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if",
 ]
 
 [[package]]
@@ -220,14 +202,19 @@
 checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
 
 [[package]]
-name = "nom"
-version = "6.2.1"
+name = "minimal-lexical"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6"
+checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677"
+
+[[package]]
+name = "nom"
+version = "7.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1"
 dependencies = [
- "bitvec",
- "funty",
  "memchr",
+ "minimal-lexical",
  "version_check",
 ]
 
@@ -245,33 +232,27 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.7"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
-name = "radium"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
-
-[[package]]
 name = "rand"
-version = "0.8.3"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
 dependencies = [
  "libc",
  "rand_chacha",
@@ -281,9 +262,9 @@
 
 [[package]]
 name = "rand_chacha"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
  "rand_core",
@@ -291,48 +272,47 @@
 
 [[package]]
 name = "rand_core"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
 dependencies = [
  "getrandom",
 ]
 
 [[package]]
 name = "rand_hc"
-version = "0.3.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
 dependencies = [
  "rand_core",
 ]
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.5"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
+checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "regex"
-version = "1.4.2"
+version = "1.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
+checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-syntax",
- "thread_local",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.21"
+version = "0.6.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 
 [[package]]
 name = "remove_dir_all"
@@ -362,18 +342,12 @@
 checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
 [[package]]
-name = "tap"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
-
-[[package]]
 name = "tempfile"
 version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
 dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
  "libc",
  "rand",
  "redox_syscall",
@@ -383,9 +357,9 @@
 
 [[package]]
 name = "termcolor"
-version = "1.1.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
 dependencies = [
  "winapi-util",
 ]
@@ -400,15 +374,6 @@
 ]
 
 [[package]]
-name = "thread_local"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
 name = "unicode-width"
 version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -416,9 +381,9 @@
 
 [[package]]
 name = "unicode-xid"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
 [[package]]
 name = "vec_map"
@@ -428,9 +393,9 @@
 
 [[package]]
 name = "version_check"
-version = "0.9.2"
+version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
 
 [[package]]
 name = "wasi"
@@ -440,10 +405,12 @@
 
 [[package]]
 name = "which"
-version = "3.1.1"
+version = "4.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
+checksum = "7cc009ab82a2afc94b9e467ab4214aee9cad1356cd9191264203d7d72006e00d"
 dependencies = [
+ "either",
+ "lazy_static",
  "libc",
 ]
 
@@ -477,9 +444,3 @@
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "wyz"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
diff --git a/Cargo.toml b/Cargo.toml
index 08e2383..8b8853a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,17 +3,16 @@
 # 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
+# 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)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
 edition = "2018"
 name = "bindgen"
-version = "0.59.1"
+version = "0.59.2"
 authors = ["Jyun-Yan You <jyyou.tw@gmail.com>", "Emilio Cobos Álvarez <emilio@crisal.io>", "Nick Fitzgerald <fitzgen@gmail.com>", "The Servo project developers"]
 build = "build.rs"
 include = ["LICENSE", "README.md", "Cargo.toml", "build.rs", "src/*.rs", "src/**/*.rs"]
@@ -38,7 +37,7 @@
 version = "1.0.3"
 
 [dependencies.cexpr]
-version = "0.5"
+version = "0.6"
 
 [dependencies.clang-sys]
 version = "1"
@@ -49,7 +48,7 @@
 optional = true
 
 [dependencies.env_logger]
-version = "0.8"
+version = "0.9.0"
 optional = true
 
 [dependencies.lazy_static]
@@ -85,7 +84,7 @@
 version = "1"
 
 [dependencies.which]
-version = "3.0"
+version = "4.2.1"
 optional = true
 default-features = false
 [dev-dependencies.clap]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 7cf5953..ba41a22 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -14,7 +14,7 @@
 repository = "https://github.com/rust-lang/rust-bindgen"
 documentation = "https://docs.rs/bindgen"
 homepage = "https://rust-lang.github.io/rust-bindgen/"
-version = "0.59.1"
+version = "0.59.2"
 edition = "2018"
 build = "build.rs"
 
@@ -47,7 +47,7 @@
 
 [dependencies]
 bitflags = "1.0.3"
-cexpr = "0.5"
+cexpr = "0.6"
 # This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
 clap = { version = "2", optional = true }
 clang-sys = { version = "1", features = ["clang_6_0"] }
@@ -56,14 +56,14 @@
 peeking_take_while = "0.1.2"
 quote = { version = "1", default-features = false }
 regex = { version = "1.0", default-features = false , features = [ "std", "unicode"]}
-which = { version = "3.0", optional = true, default-features = false }
+which = { version = "4.2.1", optional = true, default-features = false }
 shlex = "1"
 rustc-hash = "1.0.1"
 proc-macro2 = { version = "1", default-features = false }
 
 [dependencies.env_logger]
 optional = true
-version = "0.8"
+version = "0.9.0"
 
 [dependencies.log]
 optional = true
diff --git a/METADATA b/METADATA
index 87aa75a..85b1cce 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/bindgen/bindgen-0.59.1.crate"
+    value: "https://static.crates.io/crates/bindgen/bindgen-0.59.2.crate"
   }
-  version: "0.59.1"
+  version: "0.59.2"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2021
-    month: 8
-    day: 9
+    year: 2022
+    month: 3
+    day: 1
   }
 }
diff --git a/README.md b/README.md
index 00f66eb..7b2dbbc 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@
 
 ## MSRV
 
-The minimum supported Rust version is **1.44**.
+The minimum supported Rust version is **1.46**.
 
 No MSRV bump policy has been established yet, so MSRV may increase in any release.
 
diff --git a/src/clang.rs b/src/clang.rs
index db6467e..074d459 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -4,9 +4,7 @@
 #![allow(non_upper_case_globals, dead_code)]
 
 use crate::ir::context::BindgenContext;
-use cexpr;
 use clang_sys::*;
-use regex;
 use std::ffi::{CStr, CString};
 use std::fmt;
 use std::hash::Hash;
@@ -85,7 +83,7 @@
 
             let mut result = Vec::with_capacity(count);
             for i in 0..count {
-                let string_ptr = (*manglings).Strings.offset(i as isize);
+                let string_ptr = (*manglings).Strings.add(i);
                 result.push(cxstring_to_string_leaky(*string_ptr));
             }
             clang_disposeStringSet(manglings);
@@ -223,12 +221,12 @@
     /// not tracking the type declaration but the location of the cursor, given
     /// clang doesn't expose a proper declaration for these types.
     pub fn is_template_like(&self) -> bool {
-        match self.kind() {
+        matches!(
+            self.kind(),
             CXCursor_ClassTemplate |
-            CXCursor_ClassTemplatePartialSpecialization |
-            CXCursor_TypeAliasTemplateDecl => true,
-            _ => false,
-        }
+                CXCursor_ClassTemplatePartialSpecialization |
+                CXCursor_TypeAliasTemplateDecl
+        )
     }
 
     /// Is this Cursor pointing to a function-like macro definition?
@@ -275,7 +273,7 @@
             return parent.is_in_non_fully_specialized_template();
         }
 
-        return true;
+        true
     }
 
     /// Is this cursor pointing a valid referent?
@@ -402,12 +400,9 @@
     where
         Visitor: FnMut(Cursor) -> CXChildVisitResult,
     {
+        let data = &mut visitor as *mut Visitor;
         unsafe {
-            clang_visitChildren(
-                self.x,
-                visit_children::<Visitor>,
-                mem::transmute(&mut visitor),
-            );
+            clang_visitChildren(self.x, visit_children::<Visitor>, data.cast());
         }
     }
 
@@ -900,7 +895,7 @@
 where
     Visitor: FnMut(Cursor) -> CXChildVisitResult,
 {
-    let func: &mut Visitor = unsafe { mem::transmute(data) };
+    let func: &mut Visitor = unsafe { &mut *(data as *mut Visitor) };
     let child = Cursor { x: cur };
 
     (*func)(child)
@@ -1027,7 +1022,7 @@
         let s = unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) };
         // Clang 5.0 introduced changes in the spelling API so it returned the
         // full qualified name. Let's undo that here.
-        if s.split("::").all(|s| is_valid_identifier(s)) {
+        if s.split("::").all(is_valid_identifier) {
             if let Some(s) = s.split("::").last() {
                 return s.to_owned();
             }
@@ -1055,7 +1050,7 @@
                 ctx.target_pointer_size() as c_longlong
             }
             // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
-            CXType_Auto if self.is_non_deductible_auto_type() => return -6,
+            CXType_Auto if self.is_non_deductible_auto_type() => -6,
             _ => unsafe { clang_Type_getSizeOf(self.x) },
         }
     }
@@ -1068,7 +1063,7 @@
                 ctx.target_pointer_size() as c_longlong
             }
             // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
-            CXType_Auto if self.is_non_deductible_auto_type() => return -6,
+            CXType_Auto if self.is_non_deductible_auto_type() => -6,
             _ => unsafe { clang_Type_getAlignOf(self.x) },
         }
     }
@@ -1286,12 +1281,12 @@
         // nasty... But can happen in <type_traits>. Unfortunately I couldn't
         // reduce it enough :(
         self.template_args().map_or(false, |args| args.len() > 0) &&
-            match self.declaration().kind() {
+            !matches!(
+                self.declaration().kind(),
                 CXCursor_ClassTemplatePartialSpecialization |
-                CXCursor_TypeAliasTemplateDecl |
-                CXCursor_TemplateTemplateParameter => false,
-                _ => true,
-            }
+                    CXCursor_TypeAliasTemplateDecl |
+                    CXCursor_TemplateTemplateParameter
+            )
     }
 
     /// Is this type an associated template type? Eg `T::Associated` in
@@ -1406,6 +1401,12 @@
     }
 }
 
+impl fmt::Debug for SourceLocation {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self)
+    }
+}
+
 /// A comment in the source text.
 ///
 /// Comments are sort of parsed by Clang, and have a tree structure.
@@ -1704,11 +1705,7 @@
             Contents: contents.as_ptr(),
             Length: contents.as_bytes().len() as c_ulong,
         };
-        UnsavedFile {
-            x: x,
-            name: name,
-            contents: contents,
-        }
+        UnsavedFile { x, name, contents }
     }
 }
 
@@ -1819,7 +1816,7 @@
 
         if let Some(refd) = c.referenced() {
             if refd != *c {
-                println!("");
+                println!();
                 print_cursor(
                     depth,
                     String::from(prefix) + "referenced.",
@@ -1830,7 +1827,7 @@
 
         let canonical = c.canonical();
         if canonical != *c {
-            println!("");
+            println!();
             print_cursor(
                 depth,
                 String::from(prefix) + "canonical.",
@@ -1840,7 +1837,7 @@
 
         if let Some(specialized) = c.specialized() {
             if specialized != *c {
-                println!("");
+                println!();
                 print_cursor(
                     depth,
                     String::from(prefix) + "specialized.",
@@ -1850,7 +1847,7 @@
         }
 
         if let Some(parent) = c.fallible_semantic_parent() {
-            println!("");
+            println!();
             print_cursor(
                 depth,
                 String::from(prefix) + "semantic-parent.",
@@ -1898,34 +1895,34 @@
 
         let canonical = ty.canonical_type();
         if canonical != *ty {
-            println!("");
+            println!();
             print_type(depth, String::from(prefix) + "canonical.", &canonical);
         }
 
         if let Some(pointee) = ty.pointee_type() {
             if pointee != *ty {
-                println!("");
+                println!();
                 print_type(depth, String::from(prefix) + "pointee.", &pointee);
             }
         }
 
         if let Some(elem) = ty.elem_type() {
             if elem != *ty {
-                println!("");
+                println!();
                 print_type(depth, String::from(prefix) + "elements.", &elem);
             }
         }
 
         if let Some(ret) = ty.ret_type() {
             if ret != *ty {
-                println!("");
+                println!();
                 print_type(depth, String::from(prefix) + "return.", &ret);
             }
         }
 
         let named = ty.named();
         if named != *ty && named.is_valid() {
-            println!("");
+            println!();
             print_type(depth, String::from(prefix) + "named.", &named);
         }
     }
@@ -1933,13 +1930,13 @@
     print_indent(depth, "(");
     print_cursor(depth, "", c);
 
-    println!("");
+    println!();
     let ty = c.cur_type();
     print_type(depth, "type.", &ty);
 
     let declaration = ty.declaration();
     if declaration != *c && declaration.kind() != CXCursor_NoDeclFound {
-        println!("");
+        println!();
         print_cursor(depth, "type.declaration.", &declaration);
     }
 
@@ -1947,7 +1944,7 @@
     let mut found_children = false;
     c.visit(|s| {
         if !found_children {
-            println!("");
+            println!();
             found_children = true;
         }
         ast_dump(&s, depth + 1)
diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs
index 205995b..2ce6894 100644
--- a/src/codegen/helpers.rs
+++ b/src/codegen/helpers.rs
@@ -230,14 +230,14 @@
     }
 
     pub fn byte_array_expr(bytes: &[u8]) -> TokenStream {
-        let mut bytes: Vec<_> = bytes.iter().cloned().collect();
+        let mut bytes: Vec<_> = bytes.to_vec();
         bytes.push(0);
         quote! { [ #(#bytes),* ] }
     }
 
     pub fn cstr_expr(mut string: String) -> TokenStream {
         string.push('\0');
-        let b = proc_macro2::Literal::byte_string(&string.as_bytes());
+        let b = proc_macro2::Literal::byte_string(string.as_bytes());
         quote! {
             #b
         }
@@ -271,7 +271,7 @@
         }
 
         warn!("Unknown non-finite float number: {:?}", f);
-        return Err(());
+        Err(())
     }
 
     pub fn arguments_from_signature(
diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs
index 661711e..0e2cd33 100644
--- a/src/codegen/impl_debug.rs
+++ b/src/codegen/impl_debug.rs
@@ -2,7 +2,6 @@
 use crate::ir::context::BindgenContext;
 use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
 use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
-use proc_macro2;
 
 pub fn gen_debug_impl(
     ctx: &BindgenContext,
@@ -23,8 +22,8 @@
             }
             CompKind::Struct => {
                 let processed_fields = fields.iter().filter_map(|f| match f {
-                    &Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
-                    &Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
+                    Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
+                    Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
                 });
 
                 for (i, (fstring, toks)) in processed_fields.enumerate() {
@@ -186,24 +185,22 @@
                 {
                     // The simple case
                     debug_print(name, quote! { #name_ident })
+                } else if ctx.options().use_core {
+                    // There is no String in core; reducing field visibility to avoid breaking
+                    // no_std setups.
+                    Some((format!("{}: [...]", name), vec![]))
                 } else {
-                    if ctx.options().use_core {
-                        // There is no String in core; reducing field visibility to avoid breaking
-                        // no_std setups.
-                        Some((format!("{}: [...]", name), vec![]))
-                    } else {
-                        // Let's implement our own print function
-                        Some((
-                            format!("{}: [{{}}]", name),
-                            vec![quote! {
-                                self.#name_ident
-                                    .iter()
-                                    .enumerate()
-                                    .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v))
-                                    .collect::<String>()
-                            }],
-                        ))
-                    }
+                    // Let's implement our own print function
+                    Some((
+                        format!("{}: [{{}}]", name),
+                        vec![quote! {
+                            self.#name_ident
+                                .iter()
+                                .enumerate()
+                                .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v))
+                                .collect::<String>()
+                        }],
+                    ))
                 }
             }
             TypeKind::Vector(_, len) => {
diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs
index 5a1ba3f..960306f 100644
--- a/src/codegen/impl_partialeq.rs
+++ b/src/codegen/impl_partialeq.rs
@@ -2,7 +2,6 @@
 use crate::ir::context::BindgenContext;
 use crate::ir::item::{IsOpaque, Item};
 use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
-use proc_macro2;
 
 /// Generate a manual implementation of `PartialEq` trait for the
 /// specified compound type.
@@ -51,7 +50,7 @@
                 }
                 Field::Bitfields(ref bu) => {
                     for bitfield in bu.bitfields() {
-                        if let Some(_) = bitfield.name() {
+                        if bitfield.name().is_some() {
                             let getter_name = bitfield.getter_name();
                             let name_ident = ctx.rust_ident_raw(getter_name);
                             tokens.push(quote! {
@@ -104,7 +103,7 @@
         TypeKind::Opaque => quote_equals(name_ident),
 
         TypeKind::TemplateInstantiation(ref inst) => {
-            if inst.is_opaque(ctx, &ty_item) {
+            if inst.is_opaque(ctx, ty_item) {
                 quote! {
                     &self. #name_ident [..] == &other. #name_ident [..]
                 }
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 0f3337a..19886e3 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -48,7 +48,6 @@
 use quote::TokenStreamExt;
 
 use crate::{Entry, HashMap, HashSet};
-use std;
 use std::borrow::Cow;
 use std::cell::Cell;
 use std::collections::VecDeque;
@@ -58,7 +57,7 @@
 use std::str::FromStr;
 
 // Name of type defined in constified enum module
-pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &'static str = "Type";
+pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type";
 
 fn top_level_path(
     ctx: &BindgenContext,
@@ -666,10 +665,21 @@
                     match String::from_utf8(bytes.clone()) {
                         Ok(string) => {
                             let cstr = helpers::ast_ty::cstr_expr(string);
-                            result.push(quote! {
-                                #(#attrs)*
-                                pub const #canonical_ident : &'static #ty = #cstr ;
-                            });
+                            if ctx
+                                .options()
+                                .rust_features
+                                .static_lifetime_elision
+                            {
+                                result.push(quote! {
+                                    #(#attrs)*
+                                    pub const #canonical_ident : &#ty = #cstr ;
+                                });
+                            } else {
+                                result.push(quote! {
+                                    #(#attrs)*
+                                    pub const #canonical_ident : &'static #ty = #cstr ;
+                                });
+                            }
                         }
                         Err(..) => {
                             let bytes = helpers::ast_ty::byte_array_expr(bytes);
@@ -681,12 +691,11 @@
                     }
                 }
                 VarType::Float(f) => {
-                    match helpers::ast_ty::float_expr(ctx, f) {
-                        Ok(expr) => result.push(quote! {
+                    if let Ok(expr) = helpers::ast_ty::float_expr(ctx, f) {
+                        result.push(quote! {
                             #(#attrs)*
                             pub const #canonical_ident : #ty = #expr ;
-                        }),
-                        Err(..) => return,
+                        });
                     }
                 }
                 VarType::Char(c) => {
@@ -698,7 +707,7 @@
             }
         } else {
             // If necessary, apply a `#[link_name]` attribute
-            let link_name = self.mangled_name().unwrap_or(self.name());
+            let link_name = self.mangled_name().unwrap_or_else(|| self.name());
             if !utils::names_will_be_identical_after_mangling(
                 &canonical_name,
                 link_name,
@@ -756,7 +765,6 @@
                 // converted to rust types in fields, arguments, and such.
                 // NOTE(emilio): If you add to this list, make sure to also add
                 // it to BindgenContext::compute_allowlisted_and_codegen_items.
-                return;
             }
             TypeKind::TemplateInstantiation(ref inst) => {
                 inst.codegen(ctx, result, item)
@@ -886,12 +894,9 @@
 
                 // We prefer using `pub use` over `pub type` because of:
                 // https://github.com/rust-lang/rust/issues/26264
-                if inner_rust_type.to_string().chars().all(|c| match c {
-                    // These are the only characters allowed in simple
-                    // paths, eg `good::dogs::Bront`.
-                    'A'..='Z' | 'a'..='z' | '0'..='9' | ':' | '_' | ' ' => true,
-                    _ => false,
-                }) && outer_params.is_empty() &&
+                // These are the only characters allowed in simple
+                // paths, eg `good::dogs::Bront`.
+                if inner_rust_type.to_string().chars().all(|c| matches!(c, 'A'..='Z' | 'a'..='z' | '0'..='9' | ':' | '_' | ' ')) && outer_params.is_empty() &&
                     !is_opaque &&
                     alias_style == AliasVariation::TypeAlias &&
                     inner_item.expect_type().canonical_type(ctx).is_enum()
@@ -1767,7 +1772,7 @@
 
                 let inner_item = ctx.resolve_item(base.ty);
                 let mut inner = inner_item.to_rust_ty_or_opaque(ctx, &());
-                inner.append_implicit_template_params(ctx, &inner_item);
+                inner.append_implicit_template_params(ctx, inner_item);
                 let field_name = ctx.rust_ident(&base.field_name);
 
                 struct_layout.saw_base(inner_item.expect_type());
@@ -2023,6 +2028,11 @@
             attributes.push(attributes::derives(&derives))
         }
 
+        if item.annotations().must_use_type() || ctx.must_use_type_by_name(item)
+        {
+            attributes.push(attributes::must_use());
+        }
+
         let mut tokens = if is_union && struct_layout.is_rust_union() {
             quote! {
                 #( #attributes )*
@@ -2121,11 +2131,11 @@
                                 })
                                 .flat_map(|field| {
                                     let name = field.name().unwrap();
-                                    field.offset().and_then(|offset| {
+                                    field.offset().map(|offset| {
                                         let field_offset = offset / 8;
                                         let field_name = ctx.rust_ident(name);
 
-                                        Some(quote! {
+                                        quote! {
                                             assert_eq!(
                                                 unsafe {
                                                     &(*(::#prefix::ptr::null::<#canonical_ident>())).#field_name as *const _ as usize
@@ -2133,7 +2143,7 @@
                                                 #field_offset,
                                                 concat!("Offset of field: ", stringify!(#canonical_ident), "::", stringify!(#field_name))
                                             );
-                                        })
+                                        }
                                     })
                                 })
                                 .collect::<Vec<proc_macro2::TokenStream>>();
@@ -2343,7 +2353,7 @@
             return;
         }
         let function = function_item.expect_function();
-        let times_seen = function.codegen(ctx, result, &function_item);
+        let times_seen = function.codegen(ctx, result, function_item);
         let times_seen = match times_seen {
             Some(seen) => seen,
             None => return,
@@ -2409,7 +2419,7 @@
         }
 
         let mut exprs =
-            helpers::ast_ty::arguments_from_signature(&signature, ctx);
+            helpers::ast_ty::arguments_from_signature(signature, ctx);
 
         let mut stmts = vec![];
 
@@ -2466,8 +2476,7 @@
             #( #stmts );*
         };
 
-        let mut attrs = vec![];
-        attrs.push(attributes::inline());
+        let mut attrs = vec![attributes::inline()];
 
         if signature.must_use() &&
             ctx.options().rust_features().must_use_function
@@ -2508,19 +2517,13 @@
 
 impl EnumVariation {
     fn is_rust(&self) -> bool {
-        match *self {
-            EnumVariation::Rust { .. } => true,
-            _ => false,
-        }
+        matches!(*self, EnumVariation::Rust { .. })
     }
 
     /// Both the `Const` and `ModuleConsts` variants will cause this to return
     /// true.
     fn is_const(&self) -> bool {
-        match *self {
-            EnumVariation::Consts | EnumVariation::ModuleConsts => true,
-            _ => false,
-        }
+        matches!(*self, EnumVariation::Consts | EnumVariation::ModuleConsts)
     }
 }
 
@@ -2598,10 +2601,7 @@
 
     /// Returns true if the builder is for a rustified enum.
     fn is_rust_enum(&self) -> bool {
-        match *self {
-            EnumBuilder::Rust { .. } => true,
-            _ => false,
-        }
+        matches!(*self, EnumBuilder::Rust { .. })
     }
 
     /// Create a new enum given an item builder, a canonical name, a name for
@@ -2998,18 +2998,43 @@
             attrs.push(attributes::doc(comment));
         }
 
+        if item.annotations().must_use_type() || ctx.must_use_type_by_name(item)
+        {
+            attrs.push(attributes::must_use());
+        }
+
         if !variation.is_const() {
             let mut derives = derives_of_item(item, ctx);
-            // For backwards compat, enums always derive Clone/Eq/PartialEq/Hash, even
+            // For backwards compat, enums always derive Debug/Clone/Eq/PartialEq/Hash, even
             // if we don't generate those by default.
+            if !item.annotations().disallow_debug() {
+                derives.insert(DerivableTraits::DEBUG);
+            }
+            if !item.annotations().disallow_copy() {
+                derives.insert(DerivableTraits::COPY);
+            }
             derives.insert(
                 DerivableTraits::CLONE |
-                    DerivableTraits::COPY |
                     DerivableTraits::HASH |
                     DerivableTraits::PARTIAL_EQ |
                     DerivableTraits::EQ,
             );
-            let derives: Vec<_> = derives.into();
+            let mut derives: Vec<_> = derives.into();
+            for derive in item.annotations().derives().iter() {
+                if !derives.contains(&derive.as_str()) {
+                    derives.push(derive);
+                }
+            }
+
+            // The custom derives callback may return a list of derive attributes;
+            // add them to the end of the list.
+            let custom_derives;
+            if let Some(cb) = &ctx.options().parse_callbacks {
+                custom_derives = cb.add_derives(&name);
+                // In most cases this will be a no-op, since custom_derives will be empty.
+                derives.extend(custom_derives.iter().map(|s| s.as_str()));
+            };
+
             attrs.push(attributes::derives(&derives));
         }
 
@@ -3067,7 +3092,7 @@
 
         let constant_mangling_prefix = if ctx.options().prepend_enum_name {
             if enum_ty.name().is_none() {
-                parent_canonical_name.as_ref().map(|n| &**n)
+                parent_canonical_name.as_deref()
             } else {
                 Some(&*name)
             }
@@ -3626,13 +3651,12 @@
                     let void = c_void(ctx);
                     return Ok(void.to_ptr(/* is_const = */ false));
                 }
-                let template_params = item
-                    .used_template_params(ctx)
-                    .into_iter()
-                    .filter(|param| param.is_template_param(ctx, &()))
-                    .collect::<Vec<_>>();
 
-                if item.is_opaque(ctx, &()) && !template_params.is_empty() {
+                if item.is_opaque(ctx, &()) &&
+                    item.used_template_params(ctx)
+                        .into_iter()
+                        .any(|param| param.is_template_param(ctx, &()))
+                {
                     self.try_to_opaque(ctx, item)
                 } else if let Some(ty) = self
                     .name()
@@ -3661,10 +3685,8 @@
                     inner.into_resolver().through_type_refs().resolve(ctx);
                 let inner_ty = inner.expect_type();
 
-                let is_objc_pointer = match inner_ty.kind() {
-                    TypeKind::ObjCInterface(..) => true,
-                    _ => false,
-                };
+                let is_objc_pointer =
+                    matches!(inner_ty.kind(), TypeKind::ObjCInterface(..));
 
                 // Regardless if we can properly represent the inner type, we
                 // should always generate a proper pointer here, so use
@@ -3797,8 +3819,8 @@
         _: &(),
     ) -> error::Result<proc_macro2::TokenStream> {
         // TODO: we might want to consider ignoring the reference return value.
-        let ret = utils::fnsig_return_ty(ctx, &self);
-        let arguments = utils::fnsig_arguments(ctx, &self);
+        let ret = utils::fnsig_return_ty(ctx, self);
+        let arguments = utils::fnsig_arguments(ctx, self);
         let abi = self.abi();
 
         match abi {
@@ -4040,12 +4062,12 @@
             impl_items.push(impl_item);
         }
 
-        let instance_method_names: Vec<_> =
-            self.methods().iter().map(|m| m.rust_name()).collect();
-
         for class_method in self.class_methods() {
-            let ambiquity =
-                instance_method_names.contains(&class_method.rust_name());
+            let ambiquity = self
+                .methods()
+                .iter()
+                .map(|m| m.rust_name())
+                .any(|x| x == class_method.rust_name());
             let prefix = if ambiquity { "class_" } else { "" };
             let impl_item = objc_method_codegen(
                 ctx,
@@ -4637,7 +4659,7 @@
                     TypeKind::Array(t, _) => {
                         let stream =
                             if ctx.options().array_pointers_in_arguments {
-                                arg_ty.to_rust_ty_or_opaque(ctx, &arg_item)
+                                arg_ty.to_rust_ty_or_opaque(ctx, arg_item)
                             } else {
                                 t.to_rust_ty_or_opaque(ctx, &())
                             };
diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs
index 1c6b977..657be0b 100644
--- a/src/codegen/struct_layout.rs
+++ b/src/codegen/struct_layout.rs
@@ -279,6 +279,11 @@
             return None;
         }
 
+        // Padding doesn't make sense for rust unions.
+        if self.is_rust_union {
+            return None;
+        }
+
         if self.latest_offset == comp_layout.size {
             // This struct does not contain tail padding.
             return None;
@@ -428,6 +433,6 @@
 
         // Else, just align the obvious way.
         self.latest_offset += self.padding_bytes(layout);
-        return false;
+        false
     }
 }
diff --git a/src/features.rs b/src/features.rs
index 99b789e..a786f07 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -87,8 +87,9 @@
         $x_macro!(
             /// Rust stable 1.0
             => Stable_1_0 => 1.0;
-            /// Rust stable 1.1
-            => Stable_1_1 => 1.1;
+            /// Rust stable 1.17
+            ///  * Static lifetime elision ([RFC 1623](https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md))
+            => Stable_1_17 => 1.17;
             /// Rust stable 1.19
             ///  * Untagged unions ([RFC 1444](https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md))
             => Stable_1_19 => 1.19;
@@ -191,6 +192,9 @@
 // documentation for the relevant variant in the rust_target_base macro
 // definition.
 rust_feature_def!(
+    Stable_1_17 {
+        => static_lifetime_elision;
+    }
     Stable_1_19 {
         => untagged_union;
     }
@@ -249,7 +253,8 @@
     fn target_features() {
         let f_1_0 = RustFeatures::from(RustTarget::Stable_1_0);
         assert!(
-            !f_1_0.core_ffi_c_void &&
+            !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 &&
@@ -258,7 +263,8 @@
         );
         let f_1_21 = RustFeatures::from(RustTarget::Stable_1_21);
         assert!(
-            !f_1_21.core_ffi_c_void &&
+            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 &&
@@ -267,7 +273,8 @@
         );
         let f_nightly = RustFeatures::from(RustTarget::Nightly);
         assert!(
-            f_nightly.core_ffi_c_void &&
+            f_nightly.static_lifetime_elision &&
+                f_nightly.core_ffi_c_void &&
                 f_nightly.untagged_union &&
                 f_nightly.associated_const &&
                 f_nightly.builtin_clone_impls &&
@@ -286,6 +293,7 @@
     #[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);
diff --git a/src/ir/analysis/derive.rs b/src/ir/analysis/derive.rs
index 44e6702..f63458e 100644
--- a/src/ir/analysis/derive.rs
+++ b/src/ir/analysis/derive.rs
@@ -9,6 +9,7 @@
 use crate::ir::derive::CanDerive;
 use crate::ir::function::FunctionSig;
 use crate::ir::item::{IsOpaque, Item};
+use crate::ir::layout::Layout;
 use crate::ir::template::TemplateParameters;
 use crate::ir::traversal::{EdgeKind, Trace};
 use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT;
@@ -159,7 +160,7 @@
             return can_derive;
         }
 
-        if self.derive_trait.not_by_name(self.ctx, &item) {
+        if self.derive_trait.not_by_name(self.ctx, item) {
             trace!(
                 "    cannot derive {} for explicitly excluded type",
                 self.derive_trait
@@ -223,13 +224,13 @@
                 let inner_type =
                     self.ctx.resolve_type(inner).canonical_type(self.ctx);
                 if let TypeKind::Function(ref sig) = *inner_type.kind() {
-                    return self.derive_trait.can_derive_fnptr(sig);
+                    self.derive_trait.can_derive_fnptr(sig)
                 } else {
-                    return self.derive_trait.can_derive_pointer();
+                    self.derive_trait.can_derive_pointer()
                 }
             }
             TypeKind::Function(ref sig) => {
-                return self.derive_trait.can_derive_fnptr(sig)
+                self.derive_trait.can_derive_fnptr(sig)
             }
 
             // Complex cases need more information
@@ -255,7 +256,7 @@
                     return CanDerive::No;
                 }
 
-                if self.derive_trait.can_derive_large_array(&self.ctx) {
+                if self.derive_trait.can_derive_large_array(self.ctx) {
                     trace!("    array can derive {}", self.derive_trait);
                     return CanDerive::Yes;
                 }
@@ -270,7 +271,7 @@
                     "    array is small enough to derive {}",
                     self.derive_trait
                 );
-                return CanDerive::Yes;
+                CanDerive::Yes
             }
             TypeKind::Vector(t, len) => {
                 let inner_type =
@@ -285,7 +286,7 @@
                     return CanDerive::No;
                 }
                 assert_ne!(len, 0, "vectors cannot have zero length");
-                return self.derive_trait.can_derive_vector();
+                self.derive_trait.can_derive_vector()
             }
 
             TypeKind::Comp(ref info) => {
@@ -377,7 +378,7 @@
                 // Bitfield units are always represented as arrays of u8, but
                 // they're not traced as arrays, so we need to check here
                 // instead.
-                if !self.derive_trait.can_derive_large_array(&self.ctx) &&
+                if !self.derive_trait.can_derive_large_array(self.ctx) &&
                     info.has_too_large_bitfield_unit() &&
                     !item.is_opaque(self.ctx, &())
                 {
@@ -389,7 +390,7 @@
                 }
 
                 let pred = self.derive_trait.consider_edge_comp();
-                return self.constrain_join(item, pred);
+                self.constrain_join(item, pred)
             }
 
             TypeKind::ResolvedTypeRef(..) |
@@ -397,12 +398,12 @@
             TypeKind::Alias(..) |
             TypeKind::BlockPointer(..) => {
                 let pred = self.derive_trait.consider_edge_typeref();
-                return self.constrain_join(item, pred);
+                self.constrain_join(item, pred)
             }
 
             TypeKind::TemplateInstantiation(..) => {
                 let pred = self.derive_trait.consider_edge_tmpl_inst();
-                return self.constrain_join(item, pred);
+                self.constrain_join(item, pred)
             }
 
             TypeKind::Opaque => unreachable!(
@@ -470,10 +471,7 @@
     fn consider_edge_comp(&self) -> EdgePredicate {
         match self {
             DeriveTrait::PartialEqOrPartialOrd => consider_edge_default,
-            _ => |kind| match kind {
-                EdgeKind::BaseMember | EdgeKind::Field => true,
-                _ => false,
-            },
+            _ => |kind| matches!(kind, EdgeKind::BaseMember | EdgeKind::Field),
         }
     }
 
@@ -498,53 +496,35 @@
 
     fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool {
         if ctx.options().rust_features().larger_arrays {
-            match self {
-                DeriveTrait::Default => false,
-                _ => true,
-            }
+            !matches!(self, DeriveTrait::Default)
         } else {
-            match self {
-                DeriveTrait::Copy => true,
-                _ => false,
-            }
+            matches!(self, DeriveTrait::Copy)
         }
     }
 
     fn can_derive_union(&self) -> bool {
-        match self {
-            DeriveTrait::Copy => true,
-            _ => false,
-        }
+        matches!(self, DeriveTrait::Copy)
     }
 
     fn can_derive_compound_with_destructor(&self) -> bool {
-        match self {
-            DeriveTrait::Copy => false,
-            _ => true,
-        }
+        !matches!(self, DeriveTrait::Copy)
     }
 
     fn can_derive_compound_with_vtable(&self) -> bool {
-        match self {
-            DeriveTrait::Default => false,
-            _ => true,
-        }
+        !matches!(self, DeriveTrait::Default)
     }
 
     fn can_derive_compound_forward_decl(&self) -> bool {
-        match self {
-            DeriveTrait::Copy | DeriveTrait::Debug => true,
-            _ => false,
-        }
+        matches!(self, DeriveTrait::Copy | DeriveTrait::Debug)
     }
 
     fn can_derive_incomplete_array(&self) -> bool {
-        match self {
+        !matches!(
+            self,
             DeriveTrait::Copy |
-            DeriveTrait::Hash |
-            DeriveTrait::PartialEqOrPartialOrd => false,
-            _ => true,
-        }
+                DeriveTrait::Hash |
+                DeriveTrait::PartialEqOrPartialOrd
+        )
     }
 
     fn can_derive_fnptr(&self, f: &FunctionSig) -> CanDerive {
@@ -693,10 +673,10 @@
             Some(ty) => {
                 let mut can_derive = self.constrain_type(item, ty);
                 if let CanDerive::Yes = can_derive {
-                    if !self.derive_trait.can_derive_large_array(&self.ctx) &&
-                        ty.layout(self.ctx).map_or(false, |l| {
-                            l.align > RUST_DERIVE_IN_ARRAY_LIMIT
-                        })
+                    let is_reached_limit =
+                        |l: Layout| l.align > RUST_DERIVE_IN_ARRAY_LIMIT;
+                    if !self.derive_trait.can_derive_large_array(self.ctx) &&
+                        ty.layout(self.ctx).map_or(false, is_reached_limit)
                     {
                         // We have to be conservative: the struct *could* have enough
                         // padding that we emit an array that is longer than
diff --git a/src/ir/analysis/has_destructor.rs b/src/ir/analysis/has_destructor.rs
index 5fa22e3..74fd73d 100644
--- a/src/ir/analysis/has_destructor.rs
+++ b/src/ir/analysis/has_destructor.rs
@@ -41,16 +41,16 @@
 
 impl<'ctx> HasDestructorAnalysis<'ctx> {
     fn consider_edge(kind: EdgeKind) -> bool {
-        match kind {
-            // These are the only edges that can affect whether a type has a
-            // destructor or not.
+        // These are the only edges that can affect whether a type has a
+        // destructor or not.
+        matches!(
+            kind,
             EdgeKind::TypeReference |
-            EdgeKind::BaseMember |
-            EdgeKind::Field |
-            EdgeKind::TemplateArgument |
-            EdgeKind::TemplateDeclaration => true,
-            _ => false,
-        }
+                EdgeKind::BaseMember |
+                EdgeKind::Field |
+                EdgeKind::TemplateArgument |
+                EdgeKind::TemplateDeclaration
+        )
     }
 
     fn insert<Id: Into<ItemId>>(&mut self, id: Id) -> ConstrainResult {
diff --git a/src/ir/analysis/has_vtable.rs b/src/ir/analysis/has_vtable.rs
index 7f5f911..8ac47a6 100644
--- a/src/ir/analysis/has_vtable.rs
+++ b/src/ir/analysis/has_vtable.rs
@@ -79,14 +79,14 @@
 
 impl<'ctx> HasVtableAnalysis<'ctx> {
     fn consider_edge(kind: EdgeKind) -> bool {
-        match kind {
-            // These are the only edges that can affect whether a type has a
-            // vtable or not.
+        // These are the only edges that can affect whether a type has a
+        // vtable or not.
+        matches!(
+            kind,
             EdgeKind::TypeReference |
-            EdgeKind::BaseMember |
-            EdgeKind::TemplateDeclaration => true,
-            _ => false,
-        }
+                EdgeKind::BaseMember |
+                EdgeKind::TemplateDeclaration
+        )
     }
 
     fn insert<Id: Into<ItemId>>(
diff --git a/src/ir/analysis/mod.rs b/src/ir/analysis/mod.rs
index ec4d20f..eb9a1c0 100644
--- a/src/ir/analysis/mod.rs
+++ b/src/ir/analysis/mod.rs
@@ -184,7 +184,7 @@
     let mut dependencies = HashMap::default();
 
     for &item in ctx.allowlisted_items() {
-        dependencies.entry(item).or_insert(vec![]);
+        dependencies.entry(item).or_insert_with(Vec::new);
 
         {
             // We reverse our natural IR graph edges to find dependencies
@@ -197,7 +197,7 @@
                     {
                         dependencies
                             .entry(sub_item)
-                            .or_insert(vec![])
+                            .or_insert_with(Vec::new)
                             .push(item);
                     }
                 },
diff --git a/src/ir/analysis/sizedness.rs b/src/ir/analysis/sizedness.rs
index a3ef753..251c374 100644
--- a/src/ir/analysis/sizedness.rs
+++ b/src/ir/analysis/sizedness.rs
@@ -112,17 +112,17 @@
 
 impl<'ctx> SizednessAnalysis<'ctx> {
     fn consider_edge(kind: EdgeKind) -> bool {
-        match kind {
-            // These are the only edges that can affect whether a type is
-            // zero-sized or not.
+        // These are the only edges that can affect whether a type is
+        // zero-sized or not.
+        matches!(
+            kind,
             EdgeKind::TemplateArgument |
-            EdgeKind::TemplateParameterDefinition |
-            EdgeKind::TemplateDeclaration |
-            EdgeKind::TypeReference |
-            EdgeKind::BaseMember |
-            EdgeKind::Field => true,
-            _ => false,
-        }
+                EdgeKind::TemplateParameterDefinition |
+                EdgeKind::TemplateDeclaration |
+                EdgeKind::TypeReference |
+                EdgeKind::BaseMember |
+                EdgeKind::Field
+        )
     }
 
     /// Insert an incremental result, and return whether this updated our
diff --git a/src/ir/analysis/template_params.rs b/src/ir/analysis/template_params.rs
index c2f18b1..e88b774 100644
--- a/src/ir/analysis/template_params.rs
+++ b/src/ir/analysis/template_params.rs
@@ -239,7 +239,7 @@
 
         let args = instantiation
             .template_arguments()
-            .into_iter()
+            .iter()
             .map(|a| {
                 a.into_resolver()
                     .through_type_refs()
@@ -399,8 +399,8 @@
             .collect();
 
         for item in allowlisted_and_blocklisted_items {
-            dependencies.entry(item).or_insert(vec![]);
-            used.entry(item).or_insert(Some(ItemSet::new()));
+            dependencies.entry(item).or_insert_with(Vec::new);
+            used.entry(item).or_insert_with(|| Some(ItemSet::new()));
 
             {
                 // We reverse our natural IR graph edges to find dependencies
@@ -408,10 +408,11 @@
                 item.trace(
                     ctx,
                     &mut |sub_item: ItemId, _| {
-                        used.entry(sub_item).or_insert(Some(ItemSet::new()));
+                        used.entry(sub_item)
+                            .or_insert_with(|| Some(ItemSet::new()));
                         dependencies
                             .entry(sub_item)
-                            .or_insert(vec![])
+                            .or_insert_with(Vec::new)
                             .push(item);
                     },
                     &(),
@@ -421,39 +422,42 @@
             // Additionally, whether a template instantiation's template
             // arguments are used depends on whether the template declaration's
             // generic template parameters are used.
-            ctx.resolve_item(item).as_type().map(|ty| match ty.kind() {
-                &TypeKind::TemplateInstantiation(ref inst) => {
-                    let decl = ctx.resolve_type(inst.template_definition());
-                    let args = inst.template_arguments();
+            let item_kind =
+                ctx.resolve_item(item).as_type().map(|ty| ty.kind());
+            if let Some(&TypeKind::TemplateInstantiation(ref inst)) = item_kind
+            {
+                let decl = ctx.resolve_type(inst.template_definition());
+                let args = inst.template_arguments();
 
-                    // Although template definitions should always have
-                    // template parameters, there is a single exception:
-                    // opaque templates. Hence the unwrap_or.
-                    let params = decl.self_template_params(ctx);
+                // Although template definitions should always have
+                // template parameters, there is a single exception:
+                // opaque templates. Hence the unwrap_or.
+                let params = decl.self_template_params(ctx);
 
-                    for (arg, param) in args.iter().zip(params.iter()) {
-                        let arg = arg
-                            .into_resolver()
-                            .through_type_aliases()
-                            .through_type_refs()
-                            .resolve(ctx)
-                            .id();
+                for (arg, param) in args.iter().zip(params.iter()) {
+                    let arg = arg
+                        .into_resolver()
+                        .through_type_aliases()
+                        .through_type_refs()
+                        .resolve(ctx)
+                        .id();
 
-                        let param = param
-                            .into_resolver()
-                            .through_type_aliases()
-                            .through_type_refs()
-                            .resolve(ctx)
-                            .id();
+                    let param = param
+                        .into_resolver()
+                        .through_type_aliases()
+                        .through_type_refs()
+                        .resolve(ctx)
+                        .id();
 
-                        used.entry(arg).or_insert(Some(ItemSet::new()));
-                        used.entry(param).or_insert(Some(ItemSet::new()));
+                    used.entry(arg).or_insert_with(|| Some(ItemSet::new()));
+                    used.entry(param).or_insert_with(|| Some(ItemSet::new()));
 
-                        dependencies.entry(arg).or_insert(vec![]).push(param);
-                    }
+                    dependencies
+                        .entry(arg)
+                        .or_insert_with(Vec::new)
+                        .push(param);
                 }
-                _ => {}
-            });
+            }
         }
 
         if cfg!(feature = "testing_only_extra_assertions") {
@@ -482,10 +486,10 @@
         }
 
         UsedTemplateParameters {
-            ctx: ctx,
-            used: used,
-            dependencies: dependencies,
-            allowlisted_items: allowlisted_items,
+            ctx,
+            used,
+            dependencies,
+            allowlisted_items,
         }
     }
 
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
index 12664f6..9bcda50 100644
--- a/src/ir/annotations.rs
+++ b/src/ir/annotations.rs
@@ -25,7 +25,7 @@
 /// documentation:
 ///
 /// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Default, Clone, PartialEq, Debug)]
 pub struct Annotations {
     /// Whether this item is marked as opaque. Only applies to types.
     opaque: bool,
@@ -42,6 +42,8 @@
     disallow_debug: bool,
     /// Manually disable deriving/implement default on this type.
     disallow_default: bool,
+    /// Whether to add a #[must_use] annotation to this type.
+    must_use_type: bool,
     /// Whether fields should be marked as private or not. You can set this on
     /// structs (it will apply to all the fields), or individual fields.
     private_fields: Option<bool>,
@@ -75,23 +77,6 @@
     }
 }
 
-impl Default for Annotations {
-    fn default() -> Self {
-        Annotations {
-            opaque: false,
-            hide: false,
-            use_instead_of: None,
-            disallow_copy: false,
-            disallow_debug: false,
-            disallow_default: false,
-            private_fields: None,
-            accessor_kind: None,
-            constify_enum_variant: false,
-            derives: vec![],
-        }
-    }
-}
-
 impl Annotations {
     /// Construct new annotations for the given cursor and its bindgen comments
     /// (if any).
@@ -140,7 +125,7 @@
     ///
     /// That is, code for `Foo` is used to generate `Bar`.
     pub fn use_instead_of(&self) -> Option<&[String]> {
-        self.use_instead_of.as_ref().map(|s| &**s)
+        self.use_instead_of.as_deref()
     }
 
     /// The list of derives that have been specified in this annotation.
@@ -163,6 +148,11 @@
         self.disallow_default
     }
 
+    /// Should this type get a `#[must_use]` annotation?
+    pub fn must_use_type(&self) -> bool {
+        self.must_use_type
+    }
+
     /// Should the fields be private?
     pub fn private_fields(&self) -> Option<bool> {
         self.private_fields
@@ -190,6 +180,7 @@
                     "nocopy" => self.disallow_copy = true,
                     "nodebug" => self.disallow_debug = true,
                     "nodefault" => self.disallow_default = true,
+                    "mustusetype" => self.must_use_type = true,
                     "replaces" => {
                         self.use_instead_of = Some(
                             attr.value.split("::").map(Into::into).collect(),
diff --git a/src/ir/comment.rs b/src/ir/comment.rs
index 4ebe19a..c96e3eb 100644
--- a/src/ir/comment.rs
+++ b/src/ir/comment.rs
@@ -1,7 +1,5 @@
 //! Utilities for manipulating C/C++ comments.
 
-use std::iter;
-
 /// The type of a comment.
 #[derive(Debug, PartialEq, Eq)]
 enum Kind {
@@ -15,7 +13,7 @@
 
 /// Preprocesses a C/C++ comment so that it is a valid Rust comment.
 pub fn preprocess(comment: &str, indent: usize) -> String {
-    match self::kind(&comment) {
+    match self::kind(comment) {
         Some(Kind::SingleLines) => preprocess_single_lines(comment, indent),
         Some(Kind::MultiLine) => preprocess_multi_line(comment, indent),
         None => comment.to_owned(),
@@ -35,7 +33,7 @@
 
 fn make_indent(indent: usize) -> String {
     const RUST_INDENTATION: usize = 4;
-    iter::repeat(' ').take(indent * RUST_INDENTATION).collect()
+    " ".repeat(indent * RUST_INDENTATION)
 }
 
 /// Preprocesses multiple single line comments.
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
index e554f9a..a221e52 100644
--- a/src/ir/comp.rs
+++ b/src/ir/comp.rs
@@ -111,11 +111,10 @@
 
     /// Is this a virtual method?
     pub fn is_virtual(&self) -> bool {
-        match self.kind {
-            MethodKind::Virtual { .. } |
-            MethodKind::VirtualDestructor { .. } => true,
-            _ => false,
-        }
+        matches!(
+            self.kind,
+            MethodKind::Virtual { .. } | MethodKind::VirtualDestructor { .. }
+        )
     }
 
     /// Is this a static method?
@@ -630,7 +629,7 @@
                         bitfield_unit_count,
                         unit_size_in_bits,
                         unit_align,
-                        mem::replace(&mut bitfields_in_unit, vec![]),
+                        mem::take(&mut bitfields_in_unit),
                         packed,
                     );
 
@@ -639,15 +638,12 @@
                     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);
-                }
+            } else if offset != 0 &&
+                (bitfield_width == 0 ||
+                    (offset & (bitfield_align * 8 - 1)) + bitfield_width >
+                        bitfield_size * 8)
+            {
+                offset = align_to(offset, bitfield_align * 8);
             }
         }
 
@@ -706,24 +702,24 @@
 /// after.
 #[derive(Debug)]
 enum CompFields {
-    BeforeComputingBitfieldUnits(Vec<RawField>),
-    AfterComputingBitfieldUnits {
+    Before(Vec<RawField>),
+    After {
         fields: Vec<Field>,
         has_bitfield_units: bool,
     },
-    ErrorComputingBitfieldUnits,
+    Error,
 }
 
 impl Default for CompFields {
     fn default() -> CompFields {
-        CompFields::BeforeComputingBitfieldUnits(vec![])
+        CompFields::Before(vec![])
     }
 }
 
 impl CompFields {
     fn append_raw_field(&mut self, raw: RawField) {
         match *self {
-            CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
+            CompFields::Before(ref mut raws) => {
                 raws.push(raw);
             }
             _ => {
@@ -736,9 +732,7 @@
 
     fn compute_bitfield_units(&mut self, ctx: &BindgenContext, packed: bool) {
         let raws = match *self {
-            CompFields::BeforeComputingBitfieldUnits(ref mut raws) => {
-                mem::replace(raws, vec![])
-            }
+            CompFields::Before(ref mut raws) => mem::take(raws),
             _ => {
                 panic!("Already computed bitfield units");
             }
@@ -748,25 +742,23 @@
 
         match result {
             Ok((fields, has_bitfield_units)) => {
-                *self = CompFields::AfterComputingBitfieldUnits {
+                *self = CompFields::After {
                     fields,
                     has_bitfield_units,
                 };
             }
             Err(()) => {
-                *self = CompFields::ErrorComputingBitfieldUnits;
+                *self = CompFields::Error;
             }
         }
     }
 
     fn deanonymize_fields(&mut self, ctx: &BindgenContext, methods: &[Method]) {
         let fields = match *self {
-            CompFields::AfterComputingBitfieldUnits {
-                ref mut fields, ..
-            } => fields,
+            CompFields::After { ref mut fields, .. } => fields,
             // Nothing to do here.
-            CompFields::ErrorComputingBitfieldUnits => return,
-            CompFields::BeforeComputingBitfieldUnits(_) => {
+            CompFields::Error => return,
+            CompFields::Before(_) => {
                 panic!("Not yet computed bitfield units.");
             }
         };
@@ -778,7 +770,7 @@
         ) -> bool {
             methods.iter().any(|method| {
                 let method_name = ctx.resolve_func(method.signature()).name();
-                method_name == name || ctx.rust_mangle(&method_name) == name
+                method_name == name || ctx.rust_mangle(method_name) == name
             })
         }
 
@@ -820,7 +812,7 @@
         for field in fields.iter_mut() {
             match *field {
                 Field::DataMember(FieldData { ref mut name, .. }) => {
-                    if let Some(_) = *name {
+                    if name.is_some() {
                         continue;
                     }
 
@@ -858,13 +850,13 @@
         T: Tracer,
     {
         match *self {
-            CompFields::ErrorComputingBitfieldUnits => {}
-            CompFields::BeforeComputingBitfieldUnits(ref fields) => {
+            CompFields::Error => {}
+            CompFields::Before(ref fields) => {
                 for f in fields {
                     tracer.visit_kind(f.ty().into(), EdgeKind::Field);
                 }
             }
-            CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
+            CompFields::After { ref fields, .. } => {
                 for f in fields {
                     f.trace(context, tracer, &());
                 }
@@ -900,7 +892,7 @@
 
 impl FieldMethods for FieldData {
     fn name(&self) -> Option<&str> {
-        self.name.as_ref().map(|n| &**n)
+        self.name.as_deref()
     }
 
     fn ty(&self) -> TypeId {
@@ -908,7 +900,7 @@
     }
 
     fn comment(&self) -> Option<&str> {
-        self.comment.as_ref().map(|c| &**c)
+        self.comment.as_deref()
     }
 
     fn bitfield_width(&self) -> Option<u32> {
@@ -1131,11 +1123,9 @@
     /// Get this type's set of fields.
     pub fn fields(&self) -> &[Field] {
         match self.fields {
-            CompFields::ErrorComputingBitfieldUnits => &[],
-            CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
-                fields
-            }
-            CompFields::BeforeComputingBitfieldUnits(..) => {
+            CompFields::Error => &[],
+            CompFields::After { ref fields, .. } => fields,
+            CompFields::Before(..) => {
                 panic!("Should always have computed bitfield units first");
             }
         }
@@ -1143,13 +1133,9 @@
 
     fn has_fields(&self) -> bool {
         match self.fields {
-            CompFields::ErrorComputingBitfieldUnits => false,
-            CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
-                !fields.is_empty()
-            }
-            CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => {
-                !raw_fields.is_empty()
-            }
+            CompFields::Error => false,
+            CompFields::After { ref fields, .. } => !fields.is_empty(),
+            CompFields::Before(ref raw_fields) => !raw_fields.is_empty(),
         }
     }
 
@@ -1159,15 +1145,15 @@
         mut callback: impl FnMut(Layout),
     ) {
         match self.fields {
-            CompFields::ErrorComputingBitfieldUnits => return,
-            CompFields::AfterComputingBitfieldUnits { ref fields, .. } => {
+            CompFields::Error => {}
+            CompFields::After { ref fields, .. } => {
                 for field in fields.iter() {
                     if let Some(layout) = field.layout(ctx) {
                         callback(layout);
                     }
                 }
             }
-            CompFields::BeforeComputingBitfieldUnits(ref raw_fields) => {
+            CompFields::Before(ref raw_fields) => {
                 for field in raw_fields.iter() {
                     let field_ty = ctx.resolve_type(field.0.ty);
                     if let Some(layout) = field_ty.layout(ctx) {
@@ -1180,12 +1166,11 @@
 
     fn has_bitfields(&self) -> bool {
         match self.fields {
-            CompFields::ErrorComputingBitfieldUnits => false,
-            CompFields::AfterComputingBitfieldUnits {
-                has_bitfield_units,
-                ..
+            CompFields::Error => false,
+            CompFields::After {
+                has_bitfield_units, ..
             } => has_bitfield_units,
-            CompFields::BeforeComputingBitfieldUnits(_) => {
+            CompFields::Before(_) => {
                 panic!("Should always have computed bitfield units first");
             }
         }
@@ -1408,21 +1393,26 @@
                     let inner = Item::parse(cur, Some(potential_id), ctx)
                         .expect("Inner ClassDecl");
 
-                    let inner = inner.expect_type_id(ctx);
+                    // If we avoided recursion parsing this type (in
+                    // `Item::from_ty_with_id()`), then this might not be a
+                    // valid type ID, so check and gracefully handle this.
+                    if ctx.resolve_item_fallible(inner).is_some() {
+                        let inner = inner.expect_type_id(ctx);
 
-                    ci.inner_types.push(inner);
+                        ci.inner_types.push(inner);
 
-                    // A declaration of an union or a struct without name could
-                    // also be an unnamed field, unfortunately.
-                    if cur.spelling().is_empty() &&
-                        cur.kind() != CXCursor_EnumDecl
-                    {
-                        let ty = cur.cur_type();
-                        let public = cur.public_accessible();
-                        let offset = cur.offset_of_field().ok();
+                        // A declaration of an union or a struct without name
+                        // could also be an unnamed field, unfortunately.
+                        if cur.spelling().is_empty() &&
+                            cur.kind() != CXCursor_EnumDecl
+                        {
+                            let ty = cur.cur_type();
+                            let public = cur.public_accessible();
+                            let offset = cur.offset_of_field().ok();
 
-                        maybe_anonymous_struct_field =
-                            Some((inner, ty, public, offset));
+                            maybe_anonymous_struct_field =
+                                Some((inner, ty, public, offset));
+                        }
                     }
                 }
                 CXCursor_PackedAttr => {
@@ -1771,7 +1761,7 @@
         // is a type parameter), then we can't compute bitfield units. We are
         // left with no choice but to make the whole struct opaque, or else we
         // might generate structs with incorrect sizes and alignments.
-        if let CompFields::ErrorComputingBitfieldUnits = self.fields {
+        if let CompFields::Error = self.fields {
             return true;
         }
 
diff --git a/src/ir/context.rs b/src/ir/context.rs
index 72ce06b..a9e19fb 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -299,7 +299,7 @@
 /// types.
 #[derive(Eq, PartialEq, Hash, Debug)]
 enum TypeKey {
-    USR(String),
+    Usr(String),
     Declaration(Cursor),
 }
 
@@ -640,7 +640,7 @@
 
     /// Get the user-provided callbacks by reference, if any.
     pub fn parse_callbacks(&self) -> Option<&dyn ParseCallbacks> {
-        self.options().parse_callbacks.as_ref().map(|t| &**t)
+        self.options().parse_callbacks.as_deref()
     }
 
     /// Add another path to the set of included files.
@@ -702,8 +702,10 @@
         // Unnamed items can have an USR, but they can't be referenced from
         // other sites explicitly and the USR can match if the unnamed items are
         // nested, so don't bother tracking them.
-        if is_type && !is_template_instantiation && declaration.is_some() {
-            let mut declaration = declaration.unwrap();
+        if !is_type || is_template_instantiation {
+            return;
+        }
+        if let Some(mut declaration) = declaration {
             if !declaration.is_valid() {
                 if let Some(location) = location {
                     if location.is_template_like() {
@@ -732,7 +734,7 @@
             let key = if is_unnamed {
                 TypeKey::Declaration(declaration)
             } else if let Some(usr) = declaration.usr() {
-                TypeKey::USR(usr)
+                TypeKey::Usr(usr)
             } else {
                 warn!(
                     "Valid declaration with no USR: {:?}, {:?}",
@@ -829,31 +831,32 @@
     // TODO: Move all this syntax crap to other part of the code.
 
     /// Mangles a name so it doesn't conflict with any keyword.
+    #[rustfmt::skip]
     pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
-        if name.contains("@") ||
-            name.contains("?") ||
-            name.contains("$") ||
-            match name {
+        if name.contains('@') ||
+            name.contains('?') ||
+            name.contains('$') ||
+            matches!(
+                name,
                 "abstract" | "alignof" | "as" | "async" | "become" |
-                "box" | "break" | "const" | "continue" | "crate" | "do" |
-                "dyn" | "else" | "enum" | "extern" | "false" | "final" |
-                "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" |
-                "macro" | "match" | "mod" | "move" | "mut" | "offsetof" |
-                "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
-                "return" | "Self" | "self" | "sizeof" | "static" |
-                "struct" | "super" | "trait" | "true" | "type" | "typeof" |
-                "unsafe" | "unsized" | "use" | "virtual" | "where" |
-                "while" | "yield" | "str" | "bool" | "f32" | "f64" |
-                "usize" | "isize" | "u128" | "i128" | "u64" | "i64" |
-                "u32" | "i32" | "u16" | "i16" | "u8" | "i8" | "_" => true,
-                _ => false,
-            }
+                    "box" | "break" | "const" | "continue" | "crate" | "do" |
+                    "dyn" | "else" | "enum" | "extern" | "false" | "final" |
+                    "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" |
+                    "macro" | "match" | "mod" | "move" | "mut" | "offsetof" |
+                    "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
+                    "return" | "Self" | "self" | "sizeof" | "static" |
+                    "struct" | "super" | "trait" | "true" | "try" | "type" | "typeof" |
+                    "unsafe" | "unsized" | "use" | "virtual" | "where" |
+                    "while" | "yield" | "str" | "bool" | "f32" | "f64" |
+                    "usize" | "isize" | "u128" | "i128" | "u64" | "i64" |
+                    "u32" | "i32" | "u16" | "i16" | "u8" | "i8" | "_"
+            )
         {
             let mut s = name.to_owned();
             s = s.replace("@", "_");
             s = s.replace("?", "_");
             s = s.replace("$", "_");
-            s.push_str("_");
+            s.push('_');
             return Cow::Owned(s);
         }
         Cow::Borrowed(name)
@@ -903,11 +906,10 @@
                 None => continue,
             };
 
-            match *ty.kind() {
-                TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) => {
-                    typerefs.push((id, ty.clone(), loc, parent_id));
-                }
-                _ => {}
+            if let TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) =
+                *ty.kind()
+            {
+                typerefs.push((id, *ty, loc, parent_id));
             };
         }
         typerefs
@@ -978,7 +980,7 @@
         assert!(self.collected_typerefs());
 
         let need_bitfield_allocation =
-            mem::replace(&mut self.need_bitfield_allocation, vec![]);
+            mem::take(&mut self.need_bitfield_allocation);
         for id in need_bitfield_allocation {
             self.with_loaned_item(id, |ctx, item| {
                 let ty = item.kind_mut().as_type_mut().unwrap();
@@ -1121,7 +1123,8 @@
                     .ancestors(immut_self)
                     .find(|id| immut_self.resolve_item(*id).is_module())
             };
-            let new_module = new_module.unwrap_or(self.root_module.into());
+            let new_module =
+                new_module.unwrap_or_else(|| self.root_module.into());
 
             if new_module == old_module {
                 // Already in the correct module.
@@ -1329,12 +1332,12 @@
             // any sense of template parameter usage, and you're on your own.
             let mut used_params = HashMap::default();
             for &id in self.allowlisted_items() {
-                used_params.entry(id).or_insert(
+                used_params.entry(id).or_insert_with(|| {
                     id.self_template_params(self)
                         .into_iter()
                         .map(|p| p.into())
-                        .collect(),
-                );
+                        .collect()
+                });
             }
             self.used_template_parameters = Some(used_params);
         }
@@ -1420,7 +1423,7 @@
 
     fn build_root_module(id: ItemId) -> Item {
         let module = Module::new(Some("root".into()), ModuleKind::Normal);
-        Item::new(id, None, None, id, ItemKind::Module(module))
+        Item::new(id, None, None, id, ItemKind::Module(module), None)
     }
 
     /// Get the root module.
@@ -1730,6 +1733,7 @@
                             None,
                             self.current_module.into(),
                             ItemKind::Type(sub_ty),
+                            Some(child.location()),
                         );
 
                         // Bypass all the validations in add_item explicitly.
@@ -1794,6 +1798,7 @@
             None,
             self.current_module.into(),
             ItemKind::Type(ty),
+            Some(location.location()),
         );
 
         // Bypass all the validations in add_item explicitly.
@@ -1815,7 +1820,7 @@
             .or_else(|| {
                 decl.cursor()
                     .usr()
-                    .and_then(|usr| self.types.get(&TypeKey::USR(usr)))
+                    .and_then(|usr| self.types.get(&TypeKey::Usr(usr)))
             })
             .cloned()
     }
@@ -1848,32 +1853,32 @@
                 //     of it, or
                 //   * we have already parsed and resolved this type, and
                 //     there's nothing left to do.
-                if decl.cursor().is_template_like() &&
-                    *ty != decl.cursor().cur_type() &&
-                    location.is_some()
-                {
-                    let location = location.unwrap();
-
-                    // For specialized type aliases, there's no way to get the
-                    // template parameters as of this writing (for a struct
-                    // specialization we wouldn't be in this branch anyway).
-                    //
-                    // Explicitly return `None` if there aren't any
-                    // unspecialized parameters (contains any `TypeRef`) so we
-                    // resolve the canonical type if there is one and it's
-                    // exposed.
-                    //
-                    // This is _tricky_, I know :(
-                    if decl.cursor().kind() == CXCursor_TypeAliasTemplateDecl &&
-                        !location.contains_cursor(CXCursor_TypeRef) &&
-                        ty.canonical_type().is_valid_and_exposed()
+                if let Some(location) = location {
+                    if decl.cursor().is_template_like() &&
+                        *ty != decl.cursor().cur_type()
                     {
-                        return None;
-                    }
+                        // For specialized type aliases, there's no way to get the
+                        // template parameters as of this writing (for a struct
+                        // specialization we wouldn't be in this branch anyway).
+                        //
+                        // Explicitly return `None` if there aren't any
+                        // unspecialized parameters (contains any `TypeRef`) so we
+                        // resolve the canonical type if there is one and it's
+                        // exposed.
+                        //
+                        // This is _tricky_, I know :(
+                        if decl.cursor().kind() ==
+                            CXCursor_TypeAliasTemplateDecl &&
+                            !location.contains_cursor(CXCursor_TypeRef) &&
+                            ty.canonical_type().is_valid_and_exposed()
+                        {
+                            return None;
+                        }
 
-                    return self
-                        .instantiate_template(with_id, id, ty, location)
-                        .or_else(|| Some(id));
+                        return self
+                            .instantiate_template(with_id, id, ty, location)
+                            .or(Some(id));
+                    }
                 }
 
                 return Some(self.build_ty_wrapper(with_id, id, parent_id, ty));
@@ -1927,14 +1932,16 @@
     ) -> TypeId {
         let spelling = ty.spelling();
         let layout = ty.fallible_layout(self).ok();
+        let location = ty.declaration().location();
         let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
         let ty = Type::new(Some(spelling), layout, type_kind, is_const);
         let item = Item::new(
             with_id,
             None,
             None,
-            parent_id.unwrap_or(self.current_module.into()),
+            parent_id.unwrap_or_else(|| self.current_module.into()),
             ItemKind::Type(ty),
+            Some(location),
         );
         self.add_builtin_item(item);
         with_id.as_type_id_unchecked()
@@ -1995,6 +2002,7 @@
         let spelling = ty.spelling();
         let is_const = ty.is_const();
         let layout = ty.fallible_layout(self).ok();
+        let location = ty.declaration().location();
         let ty = Type::new(Some(spelling), layout, type_kind, is_const);
         let id = self.next_item_id();
         let item = Item::new(
@@ -2003,6 +2011,7 @@
             None,
             self.root_module.into(),
             ItemKind::Type(ty),
+            Some(location),
         );
         self.add_builtin_item(item);
         Some(id.as_type_id_unchecked())
@@ -2074,10 +2083,7 @@
         id: Id,
     ) -> bool {
         let id = id.into();
-        match self.replacements.get(path) {
-            Some(replaced_by) if *replaced_by != id => true,
-            _ => false,
-        }
+        matches!(self.replacements.get(path), Some(replaced_by) if *replaced_by != id)
     }
 
     /// Is the type with the given `name` marked as opaque?
@@ -2112,11 +2118,9 @@
             module_name = Some(spelling)
         }
 
-        let tokens = cursor.tokens();
-        let mut iter = tokens.iter();
         let mut kind = ModuleKind::Normal;
         let mut found_namespace_keyword = false;
-        while let Some(token) = iter.next() {
+        for token in cursor.tokens().iter() {
             match token.spelling() {
                 b"inline" => {
                     assert!(!found_namespace_keyword);
@@ -2196,6 +2200,7 @@
             None,
             self.current_module.into(),
             ItemKind::Module(module),
+            Some(cursor.location()),
         );
 
         let module_id = module.id().as_module_id_unchecked();
@@ -2243,11 +2248,6 @@
         assert!(self.in_codegen_phase());
         assert!(self.current_module == self.root_module);
 
-        let cb = match self.options.parse_callbacks {
-            Some(ref cb) => cb,
-            None => return CanDerive::No,
-        };
-
         *self
             .blocklisted_types_implement_traits
             .borrow_mut()
@@ -2257,8 +2257,27 @@
             .or_insert_with(|| {
                 item.expect_type()
                     .name()
-                    .and_then(|name| {
-                        cb.blocklisted_type_implements_trait(name, derive_trait)
+                    .and_then(|name| match self.options.parse_callbacks {
+                        Some(ref cb) => cb.blocklisted_type_implements_trait(
+                            name,
+                            derive_trait,
+                        ),
+                        // Sized integer types from <stdint.h> get mapped to Rust primitive
+                        // types regardless of whether they are blocklisted, so ensure that
+                        // standard traits are considered derivable for them too.
+                        None => match name {
+                            "int8_t" | "uint8_t" | "int16_t" | "uint16_t" |
+                            "int32_t" | "uint32_t" | "int64_t" |
+                            "uint64_t" | "uintptr_t" | "intptr_t" |
+                            "ptrdiff_t" => Some(CanDerive::Yes),
+                            "size_t" if self.options.size_t_is_usize => {
+                                Some(CanDerive::Yes)
+                            }
+                            "ssize_t" if self.options.size_t_is_usize => {
+                                Some(CanDerive::Yes)
+                            }
+                            _ => Some(CanDerive::No),
+                        },
                     })
                     .unwrap_or(CanDerive::No)
             })
@@ -2399,7 +2418,7 @@
         let codegen_items = if self.options().allowlist_recursively {
             AllowlistedItemsTraversal::new(
                 self,
-                roots.clone(),
+                roots,
                 traversal::codegen_edges,
             )
             .collect::<ItemSet>()
@@ -2663,6 +2682,12 @@
         let name = item.path_for_allowlisting(self)[1..].join("::");
         self.options().no_hash_types.matches(&name)
     }
+
+    /// Check if `--must-use-type` flag is enabled for this item.
+    pub fn must_use_type_by_name(&self, item: &Item) -> bool {
+        let name = item.path_for_allowlisting(self)[1..].join("::");
+        self.options().must_use_types.matches(&name)
+    }
 }
 
 /// A builder struct for configuring item resolution options.
@@ -2694,7 +2719,7 @@
     pub fn new<Id: Into<ItemId>>(id: Id) -> ItemResolver {
         let id = id.into();
         ItemResolver {
-            id: id,
+            id,
             through_type_refs: false,
             through_type_aliases: false,
         }
@@ -2717,8 +2742,16 @@
         assert!(ctx.collected_typerefs());
 
         let mut id = self.id;
+        let mut seen_ids = HashSet::default();
         loop {
             let item = ctx.resolve_item(id);
+
+            // Detect cycles and bail out. These can happen in certain cases
+            // involving incomplete qualified dependent types (#2085).
+            if !seen_ids.insert(id) {
+                return item;
+            }
+
             let ty_kind = item.as_type().map(|t| t.kind());
             match ty_kind {
                 Some(&TypeKind::ResolvedTypeRef(next_id))
@@ -2753,7 +2786,7 @@
     /// Construct a new `PartialType`.
     pub fn new(decl: Cursor, id: ItemId) -> PartialType {
         // assert!(decl == decl.canonical());
-        PartialType { decl: decl, id: id }
+        PartialType { decl, id }
     }
 
     /// The cursor pointing to this partial type's declaration location.
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
index 15d4136..97455c9 100644
--- a/src/ir/enum_ty.rs
+++ b/src/ir/enum_ty.rs
@@ -86,7 +86,7 @@
         } else {
             Some(type_name)
         };
-        let type_name = type_name.as_ref().map(String::as_str);
+        let type_name = type_name.as_deref();
 
         let definition = declaration.definition().unwrap_or(declaration);
         definition.visit(|cursor| {
@@ -286,7 +286,7 @@
 
     /// Get this variant's documentation.
     pub fn comment(&self) -> Option<&str> {
-        self.comment.as_ref().map(|s| &**s)
+        self.comment.as_deref()
     }
 
     /// Returns whether this variant should be enforced to be a constant by code
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 661ee59..a3a2bbf 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -123,7 +123,7 @@
 
     /// Get this function's name.
     pub fn mangled_name(&self) -> Option<&str> {
-        self.mangled_name.as_ref().map(|n| &**n)
+        self.mangled_name.as_deref()
     }
 
     /// Get this function's signature type.
@@ -187,10 +187,7 @@
 impl Abi {
     /// Returns whether this Abi is known or not.
     fn is_unknown(&self) -> bool {
-        match *self {
-            Abi::Unknown(..) => true,
-            _ => false,
-        }
+        matches!(*self, Abi::Unknown(..))
     }
 }
 
@@ -340,7 +337,7 @@
             });
 
             let cursor = arg_cur.unwrap_or(*cursor);
-            let ty = arg_ty.unwrap_or(cursor.cur_type());
+            let ty = arg_ty.unwrap_or_else(|| cursor.cur_type());
             (name, Item::from_ty_or_ref(ty, cursor, None, ctx))
         })
         .collect()
@@ -360,7 +357,7 @@
             argument_types,
             is_variadic,
             must_use,
-            abi: abi,
+            abi,
         }
     }
 
@@ -411,7 +408,7 @@
             CXCursor_CXXMethod |
             CXCursor_ObjCInstanceMethodDecl |
             CXCursor_ObjCClassMethodDecl => {
-                args_from_ty_and_cursor(&ty, &cursor, ctx)
+                args_from_ty_and_cursor(ty, &cursor, ctx)
             }
             _ => {
                 // For non-CXCursor_FunctionDecl, visiting the cursor's children
@@ -434,7 +431,7 @@
                     // right AST for functions tagged as stdcall and such...
                     //
                     // https://bugs.llvm.org/show_bug.cgi?id=45919
-                    args_from_ty_and_cursor(&ty, &cursor, ctx)
+                    args_from_ty_and_cursor(ty, &cursor, ctx)
                 } else {
                     args
                 }
@@ -522,7 +519,7 @@
             warn!("Unknown calling convention: {:?}", call_conv);
         }
 
-        Ok(Self::new(ret.into(), args, ty.is_variadic(), must_use, abi))
+        Ok(Self::new(ret, args, ty.is_variadic(), must_use, abi))
     }
 
     /// Get this function signature's return type.
@@ -567,10 +564,7 @@
             return false;
         }
 
-        match self.abi {
-            Abi::C | Abi::Unknown(..) => true,
-            _ => false,
-        }
+        matches!(self.abi, Abi::C | Abi::Unknown(..))
     }
 }
 
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 4e0ba80..8692575 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -417,6 +417,8 @@
     parent_id: ItemId,
     /// The item kind.
     kind: ItemKind,
+    /// The source location of the item.
+    location: Option<clang::SourceLocation>,
 }
 
 impl AsRef<ItemId> for Item {
@@ -433,18 +435,20 @@
         annotations: Option<Annotations>,
         parent_id: ItemId,
         kind: ItemKind,
+        location: Option<clang::SourceLocation>,
     ) -> Self {
         debug_assert!(id != parent_id || kind.is_module());
         Item {
-            id: id,
+            id,
             local_id: LazyCell::new(),
             next_child_local_id: Cell::new(1),
             canonical_name: LazyCell::new(),
             path_for_allowlisting: LazyCell::new(),
-            parent_id: parent_id,
-            comment: comment,
+            parent_id,
+            comment,
             annotations: annotations.unwrap_or_default(),
-            kind: kind,
+            kind,
+            location,
         }
     }
 
@@ -454,10 +458,15 @@
         ty: &clang::Type,
         ctx: &mut BindgenContext,
     ) -> TypeId {
+        let location = ty.declaration().location();
         let ty = Opaque::from_clang_ty(ty, ctx);
         let kind = ItemKind::Type(ty);
         let parent = ctx.root_module().into();
-        ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);
+        ctx.add_item(
+            Item::new(with_id, None, None, parent, kind, Some(location)),
+            None,
+            None,
+        );
         with_id.as_type_id_unchecked()
     }
 
@@ -612,10 +621,7 @@
 
     /// Is this item a module?
     pub fn is_module(&self) -> bool {
-        match self.kind {
-            ItemKind::Module(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, ItemKind::Module(..))
     }
 
     /// Get this item's annotations.
@@ -635,13 +641,24 @@
             return true;
         }
 
+        if !ctx.options().blocklisted_files.is_empty() {
+            if let Some(location) = &self.location {
+                let (file, _, _, _) = location.location();
+                if let Some(filename) = file.name() {
+                    if ctx.options().blocklisted_files.matches(&filename) {
+                        return true;
+                    }
+                }
+            }
+        }
+
         let path = self.path_for_allowlisting(ctx);
         let name = path[1..].join("::");
         ctx.options().blocklisted_items.matches(&name) ||
             match self.kind {
                 ItemKind::Type(..) => {
                     ctx.options().blocklisted_types.matches(&name) ||
-                        ctx.is_replaced_type(&path, self.id)
+                        ctx.is_replaced_type(path, self.id)
                 }
                 ItemKind::Function(..) => {
                     ctx.options().blocklisted_functions.matches(&name)
@@ -658,10 +675,7 @@
 
     /// Is this item a var type?
     pub fn is_var(&self) -> bool {
-        match *self.kind() {
-            ItemKind::Var(..) => true,
-            _ => false,
-        }
+        matches!(*self.kind(), ItemKind::Var(..))
     }
 
     /// Take out item NameOptions
@@ -722,7 +736,7 @@
                         .through_type_refs()
                         .resolve(ctx)
                         .push_disambiguated_name(ctx, to, level + 1);
-                    to.push_str("_");
+                    to.push('_');
                 }
                 to.push_str(&format!("close{}", level));
             }
@@ -835,7 +849,7 @@
             if ctx.options().enable_cxx_namespaces {
                 return path.last().unwrap().clone();
             }
-            return path.join("_").to_owned();
+            return path.join("_");
         }
 
         let base_name = target.base_name(ctx);
@@ -873,7 +887,7 @@
 
             // If target is anonymous we need find its first named ancestor.
             if target.is_anon() {
-                while let Some(id) = ids_iter.next() {
+                for id in ids_iter.by_ref() {
                     ids.push(id);
 
                     if !ctx.resolve_item(id).is_anon() {
@@ -1104,7 +1118,7 @@
         );
         self.annotations.opaque() ||
             self.as_type().map_or(false, |ty| ty.is_opaque(ctx, self)) ||
-            ctx.opaque_by_name(&self.path_for_allowlisting(ctx))
+            ctx.opaque_by_name(self.path_for_allowlisting(ctx))
     }
 }
 
@@ -1114,20 +1128,16 @@
 {
     fn has_vtable(&self, ctx: &BindgenContext) -> bool {
         let id: ItemId = (*self).into();
-        id.as_type_id(ctx)
-            .map_or(false, |id| match ctx.lookup_has_vtable(id) {
-                HasVtableResult::No => false,
-                _ => true,
-            })
+        id.as_type_id(ctx).map_or(false, |id| {
+            !matches!(ctx.lookup_has_vtable(id), HasVtableResult::No)
+        })
     }
 
     fn has_vtable_ptr(&self, ctx: &BindgenContext) -> bool {
         let id: ItemId = (*self).into();
-        id.as_type_id(ctx)
-            .map_or(false, |id| match ctx.lookup_has_vtable(id) {
-                HasVtableResult::SelfHasVtable => true,
-                _ => false,
-            })
+        id.as_type_id(ctx).map_or(false, |id| {
+            matches!(ctx.lookup_has_vtable(id), HasVtableResult::SelfHasVtable)
+        })
     }
 }
 
@@ -1307,7 +1317,7 @@
         let id = ctx.next_item_id();
         let module = ctx.root_module().into();
         ctx.add_item(
-            Item::new(id, None, None, module, ItemKind::Type(ty)),
+            Item::new(id, None, None, module, ItemKind::Type(ty), None),
             None,
             None,
         );
@@ -1345,6 +1355,7 @@
                                 annotations,
                                 relevant_parent_id,
                                 ItemKind::$what(item),
+                                Some(cursor.location()),
                             ),
                             declaration,
                             Some(cursor),
@@ -1392,7 +1403,7 @@
                     }
                     ctx.known_semantic_parent(definition)
                         .or(parent_id)
-                        .unwrap_or(ctx.current_module().into())
+                        .unwrap_or_else(|| ctx.current_module().into())
                 }
                 None => relevant_parent_id,
             };
@@ -1524,8 +1535,9 @@
                 potential_id,
                 None,
                 None,
-                parent_id.unwrap_or(current_module.into()),
+                parent_id.unwrap_or_else(|| current_module.into()),
                 ItemKind::Type(Type::new(None, None, kind, is_const)),
+                Some(location.location()),
             ),
             None,
             None,
@@ -1594,8 +1606,8 @@
         }
 
         let decl = {
-            let decl = ty.declaration();
-            decl.definition().unwrap_or(decl)
+            let canonical_def = ty.canonical_type().declaration().definition();
+            canonical_def.unwrap_or_else(|| ty.declaration())
         };
 
         let comment = decl.raw_comment().or_else(|| location.raw_comment());
@@ -1603,7 +1615,7 @@
             Annotations::new(&decl).or_else(|| Annotations::new(&location));
 
         if let Some(ref annotations) = annotations {
-            if let Some(ref replaced) = annotations.use_instead_of() {
+            if let Some(replaced) = annotations.use_instead_of() {
                 ctx.replace(replaced, id);
             }
         }
@@ -1657,6 +1669,7 @@
                         annotations,
                         relevant_parent_id,
                         ItemKind::Type(item),
+                        Some(location.location()),
                     ),
                     declaration,
                     Some(location),
@@ -1851,11 +1864,7 @@
                 clang_sys::CXChildVisit_Continue
             });
 
-            if let Some(def) = definition {
-                def
-            } else {
-                return None;
-            }
+            definition?
         };
         assert!(is_template_with_spelling(&definition, &ty_spelling));
 
@@ -1889,6 +1898,7 @@
             None,
             parent,
             ItemKind::Type(Type::named(name)),
+            Some(location.location()),
         );
         ctx.add_type_param(item, definition);
         Some(id.as_type_id_unchecked())
@@ -1939,7 +1949,7 @@
             path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
         }
 
-        return path;
+        path
     }
 
     fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
@@ -1972,8 +1982,8 @@
     /// Construct a new `NameOptions`
     pub fn new(item: &'a Item, ctx: &'a BindgenContext) -> Self {
         NameOptions {
-            item: item,
-            ctx: ctx,
+            item,
+            ctx,
             within_namespaces: false,
             user_mangled: UserMangled::Yes,
         }
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index 28a6604..6cf9113 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -64,7 +64,7 @@
             next_align *= 2;
         }
         Layout {
-            size: size,
+            size,
             align: next_align / 2,
             packed: false,
         }
diff --git a/src/ir/module.rs b/src/ir/module.rs
index 13b7c19..d5aca94 100644
--- a/src/ir/module.rs
+++ b/src/ir/module.rs
@@ -32,15 +32,15 @@
     /// Construct a new `Module`.
     pub fn new(name: Option<String>, kind: ModuleKind) -> Self {
         Module {
-            name: name,
-            kind: kind,
+            name,
+            kind,
             children: ItemSet::new(),
         }
     }
 
     /// Get this module's name.
     pub fn name(&self) -> Option<&str> {
-        self.name.as_ref().map(|n| &**n)
+        self.name.as_deref()
     }
 
     /// Get a mutable reference to this module's children.
diff --git a/src/ir/objc.rs b/src/ir/objc.rs
index 91855c6..0845ad0 100644
--- a/src/ir/objc.rs
+++ b/src/ir/objc.rs
@@ -89,12 +89,10 @@
     pub fn rust_name(&self) -> String {
         if let Some(ref cat) = self.category {
             format!("{}_{}", self.name(), cat)
+        } else if self.is_protocol {
+            format!("P{}", self.name())
         } else {
-            if self.is_protocol {
-                format!("P{}", self.name())
-            } else {
-                format!("I{}", self.name().to_owned())
-            }
+            format!("I{}", self.name().to_owned())
         }
     }
 
@@ -149,28 +147,34 @@
                     // Gather protocols this interface conforms to
                     let needle = format!("P{}", c.spelling());
                     let items_map = ctx.items();
-                    debug!("Interface {} conforms to {}, find the item", interface.name, needle);
+                    debug!(
+                        "Interface {} conforms to {}, find the item",
+                        interface.name, needle
+                    );
 
-                    for (id, item) in items_map
-                    {
+                    for (id, item) in items_map {
                         if let Some(ty) = item.as_type() {
-                            match *ty.kind() {
-                                TypeKind::ObjCInterface(ref protocol) => {
-                                    if protocol.is_protocol
-                                    {
-                                        debug!("Checking protocol {}, ty.name {:?}", protocol.name, ty.name());
-                                        if Some(needle.as_ref()) == ty.name() {
-                                            debug!("Found conforming protocol {:?}", item);
-                                            interface.conforms_to.push(id);
-                                            break;
-                                        }
+                            if let TypeKind::ObjCInterface(ref protocol) =
+                                *ty.kind()
+                            {
+                                if protocol.is_protocol {
+                                    debug!(
+                                        "Checking protocol {}, ty.name {:?}",
+                                        protocol.name,
+                                        ty.name()
+                                    );
+                                    if Some(needle.as_ref()) == ty.name() {
+                                        debug!(
+                                            "Found conforming protocol {:?}",
+                                            item
+                                        );
+                                        interface.conforms_to.push(id);
+                                        break;
                                     }
                                 }
-                                _ => {}
                             }
                         }
                     }
-
                 }
                 CXCursor_ObjCInstanceMethodDecl |
                 CXCursor_ObjCClassMethodDecl => {
@@ -178,8 +182,10 @@
                     let signature =
                         FunctionSig::from_ty(&c.cur_type(), &c, ctx)
                             .expect("Invalid function sig");
-                    let is_class_method = c.kind() == CXCursor_ObjCClassMethodDecl;
-                    let method = ObjCMethod::new(&name, signature, is_class_method);
+                    let is_class_method =
+                        c.kind() == CXCursor_ObjCClassMethodDecl;
+                    let method =
+                        ObjCMethod::new(&name, signature, is_class_method);
                     interface.add_method(method);
                 }
                 CXCursor_TemplateTypeParameter => {
@@ -189,7 +195,7 @@
                 CXCursor_ObjCSuperClassRef => {
                     let item = Item::from_ty_or_ref(c.cur_type(), c, None, ctx);
                     interface.parent_class = Some(item.into());
-                },
+                }
                 _ => {}
             }
             CXChildVisit_Continue
@@ -218,7 +224,7 @@
 
         ObjCMethod {
             name: name.to_owned(),
-            rust_name: rust_name.to_owned(),
+            rust_name,
             signature,
             is_class_method,
         }
@@ -261,7 +267,7 @@
             .collect();
 
         // No arguments
-        if args.len() == 0 && split_name.len() == 1 {
+        if args.is_empty() && split_name.len() == 1 {
             let name = &split_name[0];
             return quote! {
                 #name
@@ -269,13 +275,12 @@
         }
 
         // Check right amount of arguments
-        if args.len() != split_name.len() - 1 {
-            panic!(
-                "Incorrect method name or arguments for objc method, {:?} vs {:?}",
-                args,
-                split_name,
-            );
-        }
+        assert!(
+            args.len() == split_name.len() - 1,
+            "Incorrect method name or arguments for objc method, {:?} vs {:?}",
+            args,
+            split_name
+        );
 
         // Get arguments without type signatures to pass to `msg_send!`
         let mut args_without_types = vec![];
diff --git a/src/ir/template.rs b/src/ir/template.rs
index b519fff..8b06748 100644
--- a/src/ir/template.rs
+++ b/src/ir/template.rs
@@ -134,10 +134,10 @@
     where
         Self: ItemAncestors,
     {
-        let ancestors: Vec<_> = self.ancestors(ctx).collect();
+        let mut ancestors: Vec<_> = self.ancestors(ctx).collect();
+        ancestors.reverse();
         ancestors
             .into_iter()
-            .rev()
             .flat_map(|id| id.self_template_params(ctx).into_iter())
             .collect()
     }
diff --git a/src/ir/traversal.rs b/src/ir/traversal.rs
index 430dd02..088e744 100644
--- a/src/ir/traversal.rs
+++ b/src/ir/traversal.rs
@@ -24,9 +24,9 @@
     }
 }
 
-impl Into<ItemId> for Edge {
-    fn into(self) -> ItemId {
-        self.to
+impl From<Edge> for ItemId {
+    fn from(val: Edge) -> Self {
+        val.to
     }
 }
 
@@ -424,10 +424,10 @@
         }
 
         ItemTraversal {
-            ctx: ctx,
-            seen: seen,
-            queue: queue,
-            predicate: predicate,
+            ctx,
+            seen,
+            queue,
+            predicate,
             currently_traversing: None,
         }
     }
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index e049ed6..d573408 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -87,23 +87,17 @@
 
     /// Get this type's name.
     pub fn name(&self) -> Option<&str> {
-        self.name.as_ref().map(|name| &**name)
+        self.name.as_deref()
     }
 
     /// Whether this is a block pointer type.
     pub fn is_block_pointer(&self) -> bool {
-        match self.kind {
-            TypeKind::BlockPointer(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::BlockPointer(..))
     }
 
     /// Is this a compound type?
     pub fn is_comp(&self) -> bool {
-        match self.kind {
-            TypeKind::Comp(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Comp(..))
     }
 
     /// Is this a union?
@@ -116,58 +110,43 @@
 
     /// Is this type of kind `TypeKind::TypeParam`?
     pub fn is_type_param(&self) -> bool {
-        match self.kind {
-            TypeKind::TypeParam => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::TypeParam)
     }
 
     /// Is this a template instantiation type?
     pub fn is_template_instantiation(&self) -> bool {
-        match self.kind {
-            TypeKind::TemplateInstantiation(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::TemplateInstantiation(..))
     }
 
     /// Is this a template alias type?
     pub fn is_template_alias(&self) -> bool {
-        match self.kind {
-            TypeKind::TemplateAlias(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::TemplateAlias(..))
     }
 
     /// Is this a function type?
     pub fn is_function(&self) -> bool {
-        match self.kind {
-            TypeKind::Function(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Function(..))
     }
 
     /// Is this an enum type?
     pub fn is_enum(&self) -> bool {
-        match self.kind {
-            TypeKind::Enum(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Enum(..))
     }
 
     /// Is this either a builtin or named type?
     pub fn is_builtin_or_type_param(&self) -> bool {
-        match self.kind {
+        matches!(
+            self.kind,
             TypeKind::Void |
-            TypeKind::NullPtr |
-            TypeKind::Function(..) |
-            TypeKind::Array(..) |
-            TypeKind::Reference(..) |
-            TypeKind::Pointer(..) |
-            TypeKind::Int(..) |
-            TypeKind::Float(..) |
-            TypeKind::TypeParam => true,
-            _ => false,
-        }
+                TypeKind::NullPtr |
+                TypeKind::Function(..) |
+                TypeKind::Array(..) |
+                TypeKind::Reference(..) |
+                TypeKind::Pointer(..) |
+                TypeKind::Int(..) |
+                TypeKind::Float(..) |
+                TypeKind::TypeParam
+        )
     }
 
     /// Creates a new named type, with name `name`.
@@ -178,26 +157,17 @@
 
     /// Is this a floating point type?
     pub fn is_float(&self) -> bool {
-        match self.kind {
-            TypeKind::Float(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Float(..))
     }
 
     /// Is this a boolean type?
     pub fn is_bool(&self) -> bool {
-        match self.kind {
-            TypeKind::Int(IntKind::Bool) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Int(IntKind::Bool))
     }
 
     /// Is this an integer type?
     pub fn is_integer(&self) -> bool {
-        match self.kind {
-            TypeKind::Int(..) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::Int(..))
     }
 
     /// Cast this type to an integer kind, or `None` if it is not an integer
@@ -216,19 +186,15 @@
 
     /// Is this a reference to another type?
     pub fn is_type_ref(&self) -> bool {
-        match self.kind {
-            TypeKind::ResolvedTypeRef(_) |
-            TypeKind::UnresolvedTypeRef(_, _, _) => true,
-            _ => false,
-        }
+        matches!(
+            self.kind,
+            TypeKind::ResolvedTypeRef(_) | TypeKind::UnresolvedTypeRef(_, _, _)
+        )
     }
 
     /// Is this an unresolved reference?
     pub fn is_unresolved_ref(&self) -> bool {
-        match self.kind {
-            TypeKind::UnresolvedTypeRef(_, _, _) => true,
-            _ => false,
-        }
+        matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _))
     }
 
     /// Is this a incomplete array type?
@@ -278,14 +244,14 @@
         match self.kind {
             TypeKind::TypeParam => {
                 let name = self.name().expect("Unnamed named type?");
-                !clang::is_valid_identifier(&name)
+                !clang::is_valid_identifier(name)
             }
             _ => false,
         }
     }
 
     /// Takes `name`, and returns a suitable identifier representation for it.
-    fn sanitize_name<'a>(name: &'a str) -> Cow<'a, str> {
+    fn sanitize_name(name: &str) -> Cow<str> {
         if clang::is_valid_identifier(name) {
             return Cow::Borrowed(name);
         }
@@ -300,12 +266,8 @@
         ctx: &BindgenContext,
     ) -> Option<Cow<'a, str>> {
         let name_info = match *self.kind() {
-            TypeKind::Pointer(inner) => {
-                Some((inner.into(), Cow::Borrowed("ptr")))
-            }
-            TypeKind::Reference(inner) => {
-                Some((inner.into(), Cow::Borrowed("ref")))
-            }
+            TypeKind::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()))
             }
@@ -375,16 +337,16 @@
     /// There are some types we don't want to stop at when finding an opaque
     /// item, so we can arrive to the proper item that needs to be generated.
     pub fn should_be_traced_unconditionally(&self) -> bool {
-        match self.kind {
+        matches!(
+            self.kind,
             TypeKind::Comp(..) |
-            TypeKind::Function(..) |
-            TypeKind::Pointer(..) |
-            TypeKind::Array(..) |
-            TypeKind::Reference(..) |
-            TypeKind::TemplateInstantiation(..) |
-            TypeKind::ResolvedTypeRef(..) => true,
-            _ => false,
-        }
+                TypeKind::Function(..) |
+                TypeKind::Pointer(..) |
+                TypeKind::Array(..) |
+                TypeKind::Reference(..) |
+                TypeKind::TemplateInstantiation(..) |
+                TypeKind::ResolvedTypeRef(..)
+        )
     }
 }
 
@@ -791,7 +753,7 @@
             (ty.template_args().is_some() && ty_kind != CXType_Typedef)
         {
             // This is a template instantiation.
-            match TemplateInstantiation::from_ty(&ty, ctx) {
+            match TemplateInstantiation::from_ty(ty, ctx) {
                 Some(inst) => TypeKind::TemplateInstantiation(inst),
                 None => TypeKind::Opaque,
             }
@@ -1120,7 +1082,16 @@
                     let inner = cursor.typedef_type().expect("Not valid Type?");
                     let inner =
                         Item::from_ty_or_ref(inner, location, None, ctx);
-                    TypeKind::Alias(inner)
+                    if inner == potential_id {
+                        warn!(
+                            "Generating oqaque type instead of self-referential \
+                            typedef");
+                        // This can happen if we bail out of recursive situations
+                        // within the clang parsing.
+                        TypeKind::Opaque
+                    } else {
+                        TypeKind::Alias(inner)
+                    }
                 }
                 CXType_Enum => {
                     let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
diff --git a/src/ir/var.rs b/src/ir/var.rs
index 49c4f30..cd17937 100644
--- a/src/ir/var.rs
+++ b/src/ir/var.rs
@@ -88,7 +88,7 @@
 
     /// Get this variable's mangled name.
     pub fn mangled_name(&self) -> Option<&str> {
-        self.mangled_name.as_ref().map(|n| &**n)
+        self.mangled_name.as_deref()
     }
 }
 
@@ -282,7 +282,7 @@
                             .parse_callbacks()
                             .and_then(|c| c.int_macro(&name, value))
                             .unwrap_or_else(|| {
-                                default_macro_constant_type(&ctx, value)
+                                default_macro_constant_type(ctx, value)
                             });
 
                         (TypeKind::Int(kind), VarType::Int(value))
@@ -398,11 +398,8 @@
 
     let parser = expr::IdentifierParser::new(ctx.parsed_macros());
 
-    match parser.macro_definition(&cexpr_tokens) {
-        Ok((_, (id, val))) => {
-            return Some((id.into(), val));
-        }
-        _ => {}
+    if let Ok((_, (id, val))) = parser.macro_definition(&cexpr_tokens) {
+        return Some((id.into(), val));
     }
 
     // Try without the last token, to workaround a libclang bug in versions
diff --git a/src/lib.rs b/src/lib.rs
index 01adba3..9a90dac 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,7 +89,7 @@
 pub(crate) use std::collections::hash_map::Entry;
 
 /// Default prefix for the anon fields.
-pub const DEFAULT_ANON_FIELDS_PREFIX: &'static str = "__bindgen_anon_";
+pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_";
 
 fn file_is_cpp(name_file: &str) -> bool {
     name_file.ends_with(".hpp") ||
@@ -308,6 +308,7 @@
             (&self.options.blocklisted_types, "--blocklist-type"),
             (&self.options.blocklisted_functions, "--blocklist-function"),
             (&self.options.blocklisted_items, "--blocklist-item"),
+            (&self.options.blocklisted_files, "--blocklist-file"),
             (&self.options.opaque_types, "--opaque-type"),
             (&self.options.allowlisted_functions, "--allowlist-function"),
             (&self.options.allowlisted_types, "--allowlist-type"),
@@ -317,6 +318,7 @@
             (&self.options.no_debug_types, "--no-debug"),
             (&self.options.no_default_types, "--no-default"),
             (&self.options.no_hash_types, "--no-hash"),
+            (&self.options.must_use_types, "--must-use-type"),
         ];
 
         for (set, flag) in regex_sets {
@@ -820,6 +822,13 @@
         self
     }
 
+    /// Hide any contents of the given file from the generated bindings,
+    /// regardless of whether it's a type, function, module etc.
+    pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder {
+        self.options.blocklisted_files.insert(arg);
+        self
+    }
+
     /// Treat the given type as opaque in the generated bindings. Regular
     /// expressions are supported.
     ///
@@ -1588,6 +1597,13 @@
         self
     }
 
+    /// Add `#[must_use]` for the given type. Regular
+    /// expressions are supported.
+    pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder {
+        self.options.must_use_types.insert(arg.into());
+        self
+    }
+
     /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut)
     pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self {
         self.options.array_pointers_in_arguments = doit;
@@ -1661,6 +1677,10 @@
     /// blocklisted and should not appear in the generated code.
     blocklisted_items: RegexSet,
 
+    /// The set of files whose contents should be blocklisted and should not
+    /// appear in the generated code.
+    blocklisted_files: RegexSet,
+
     /// The set of types that should be treated as opaque structures in the
     /// generated code.
     opaque_types: RegexSet,
@@ -1928,6 +1948,9 @@
     /// The set of types that we should not derive `Hash` for.
     no_hash_types: RegexSet,
 
+    /// The set of types that we should be annotated with `#[must_use]`.
+    must_use_types: RegexSet,
+
     /// Decide if C arrays should be regular pointers in rust or array pointers
     array_pointers_in_arguments: bool,
 
@@ -1971,6 +1994,7 @@
             &mut self.blocklisted_types,
             &mut self.blocklisted_functions,
             &mut self.blocklisted_items,
+            &mut self.blocklisted_files,
             &mut self.opaque_types,
             &mut self.bitfield_enums,
             &mut self.constified_enums,
@@ -1986,6 +2010,7 @@
             &mut self.no_debug_types,
             &mut self.no_default_types,
             &mut self.no_hash_types,
+            &mut self.must_use_types,
         ];
         let record_matches = self.record_matches;
         for regex_set in &mut regex_sets {
@@ -2017,6 +2042,7 @@
             blocklisted_types: Default::default(),
             blocklisted_functions: Default::default(),
             blocklisted_items: Default::default(),
+            blocklisted_files: Default::default(),
             opaque_types: Default::default(),
             rustfmt_path: Default::default(),
             depfile: Default::default(),
@@ -2090,6 +2116,7 @@
             no_debug_types: Default::default(),
             no_default_types: Default::default(),
             no_hash_types: Default::default(),
+            must_use_types: Default::default(),
             array_pointers_in_arguments: false,
             wasm_import_module_name: None,
             dynamic_library_name: None,
@@ -2135,7 +2162,7 @@
     module: proc_macro2::TokenStream,
 }
 
-pub(crate) const HOST_TARGET: &'static str =
+pub(crate) const HOST_TARGET: &str =
     include_str!(concat!(env!("OUT_DIR"), "/host-target.txt"));
 
 // Some architecture triplets are different between rust and libclang, see #1211
@@ -2143,7 +2170,8 @@
 fn rust_to_clang_target(rust_target: &str) -> String {
     if rust_target.starts_with("aarch64-apple-") {
         let mut clang_target = "arm64-apple-".to_owned();
-        clang_target.push_str(&rust_target["aarch64-apple-".len()..]);
+        clang_target
+            .push_str(rust_target.strip_prefix("aarch64-apple-").unwrap());
         return clang_target;
     }
     rust_target.to_owned()
@@ -2265,10 +2293,7 @@
 
             // Whether we are working with C or C++ inputs.
             let is_cpp = args_are_cpp(&options.clang_args) ||
-                options
-                    .input_header
-                    .as_ref()
-                    .map_or(false, |i| file_is_cpp(&i));
+                options.input_header.as_deref().map_or(false, file_is_cpp);
 
             let search_paths = if is_cpp {
                 clang.cpp_search_paths
@@ -2356,15 +2381,6 @@
         })
     }
 
-    /// Convert these bindings into source text (with raw lines prepended).
-    pub fn to_string(&self) -> String {
-        let mut bytes = vec![];
-        self.write(Box::new(&mut bytes) as Box<dyn Write>)
-            .expect("writing to a vec cannot fail");
-        String::from_utf8(bytes)
-            .expect("we should only write bindings that are valid utf-8")
-    }
-
     /// Write these bindings as source text to a file.
     pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
         let file = OpenOptions::new()
@@ -2379,7 +2395,7 @@
     /// Write these bindings as source text to the given `Write`able.
     pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> {
         if !self.options.disable_header_comment {
-            let version = Some("0.59.1");
+            let version = Some("0.59.2");
             let header = format!(
                 "/* automatically generated by rust-bindgen {} */\n\n",
                 version.unwrap_or("(unknown version)")
@@ -2414,7 +2430,7 @@
     }
 
     /// Gets the rustfmt path to rustfmt the generated bindings.
-    fn rustfmt_path<'a>(&'a self) -> io::Result<Cow<'a, PathBuf>> {
+    fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> {
         debug_assert!(self.options.rustfmt_bindings);
         if let Some(ref p) = self.options.rustfmt_path {
             return Ok(Cow::Borrowed(p));
@@ -2505,6 +2521,18 @@
     }
 }
 
+impl std::fmt::Display for Bindings {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut bytes = vec![];
+        self.write(Box::new(&mut bytes) as Box<dyn Write>)
+            .expect("writing to a vec cannot fail");
+        f.write_str(
+            std::str::from_utf8(&bytes)
+                .expect("we should only write bindings that are valid utf-8"),
+        )
+    }
+}
+
 /// Determines whether the given cursor is in any of the files matched by the
 /// options.
 fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool {
@@ -2553,7 +2581,7 @@
     if context.options().emit_ast {
         fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult {
             if !cur.is_builtin() {
-                clang::ast_dump(&cur, 0)
+                clang::ast_dump(cur, 0)
             } else {
                 CXChildVisit_Continue
             }
@@ -2590,26 +2618,19 @@
     let raw_v: String = clang::extract_clang_version();
     let split_v: Option<Vec<&str>> = raw_v
         .split_whitespace()
-        .filter(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit()))
-        .next()
+        .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit()))
         .map(|v| v.split('.').collect());
-    match split_v {
-        Some(v) => {
-            if v.len() >= 2 {
-                let maybe_major = v[0].parse::<u32>();
-                let maybe_minor = v[1].parse::<u32>();
-                match (maybe_major, maybe_minor) {
-                    (Ok(major), Ok(minor)) => {
-                        return ClangVersion {
-                            parsed: Some((major, minor)),
-                            full: raw_v.clone(),
-                        }
-                    }
-                    _ => {}
-                }
+    if let Some(v) = split_v {
+        if v.len() >= 2 {
+            let maybe_major = v[0].parse::<u32>();
+            let maybe_minor = v[1].parse::<u32>();
+            if let (Ok(major), Ok(minor)) = (maybe_major, maybe_minor) {
+                return ClangVersion {
+                    parsed: Some((major, minor)),
+                    full: raw_v.clone(),
+                };
             }
         }
-        None => {}
     };
     ClangVersion {
         parsed: None,
@@ -2635,7 +2656,7 @@
 /// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed
 /// line
 ///
-/// When running in side a `build.rs` script, this can be used to make cargo invalidate the
+/// When running inside a `build.rs` script, this can be used to make cargo invalidate the
 /// generated bindings whenever any of the files included from the header change:
 /// ```
 /// use bindgen::builder;
diff --git a/src/log_stubs.rs b/src/log_stubs.rs
index 4af496c..8315983 100644
--- a/src/log_stubs.rs
+++ b/src/log_stubs.rs
@@ -1,32 +1,32 @@
 #![allow(unused)]
 
 macro_rules! log {
-    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {
+    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {{
         let _ = $target;
         let _ = log!($lvl, $($arg)+);
-    };
+    }};
     ($lvl:expr, $($arg:tt)+) => {{
         let _ = $lvl;
         let _ = format_args!($($arg)+);
     }};
 }
 macro_rules! error {
-    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
-    ($($arg:tt)*) => { log!("", $($arg)*); };
+    (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+    ($($arg:tt)+) => { log!("", $($arg)+) };
 }
 macro_rules! warn {
-    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
-    ($($arg:tt)*) => { log!("", $($arg)*); };
+    (target: $target:expr, $($arg:tt)*) => { log!(target: $target, "", $($arg)*) };
+    ($($arg:tt)*) => { log!("", $($arg)*) };
 }
 macro_rules! info {
-    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
-    ($($arg:tt)*) => { log!("", $($arg)*); };
+    (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+    ($($arg:tt)+) => { log!("", $($arg)+) };
 }
 macro_rules! debug {
-    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
-    ($($arg:tt)*) => { log!("", $($arg)*); };
+    (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+    ($($arg:tt)+) => { log!("", $($arg)+) };
 }
 macro_rules! trace {
-    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
-    ($($arg:tt)*) => { log!("", $($arg)*); };
+    (target: $target:expr, $($arg:tt)+) => { log!(target: $target, "", $($arg)+) };
+    ($($arg:tt)+) => { log!("", $($arg)+) };
 }
diff --git a/src/main.rs b/src/main.rs
index 1768ed8..f3398db 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,7 +37,7 @@
     );
 
     if expected_version.is_some() {
-        assert_eq!(version.parsed, version.parsed);
+        // assert_eq!(version.parsed, version.parsed);
     }
 }
 
@@ -45,9 +45,7 @@
     #[cfg(feature = "logging")]
     env_logger::init();
 
-    let bind_args: Vec<_> = env::args().collect();
-
-    match builder_from_flags(bind_args.into_iter()) {
+    match builder_from_flags(env::args()) {
         Ok((builder, output, verbose)) => {
             clang_version_check();
             let builder_result = panic::catch_unwind(|| {
diff --git a/src/options.rs b/src/options.rs
index c02f275..94f3047 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -23,7 +23,7 @@
     );
 
     let matches = App::new("bindgen")
-        .version(Some("0.59.1").unwrap_or("unknown"))
+        .version(Some("0.59.2").unwrap_or("unknown"))
         .about("Generates Rust bindings from C/C++ headers.")
         .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...")
         .args(&[
@@ -164,6 +164,14 @@
                 .takes_value(true)
                 .multiple(true)
                 .number_of_values(1),
+            Arg::with_name("blocklist-file")
+                .alias("blacklist-file")
+                .long("blocklist-file")
+                .help("Mark all contents of <path> as hidden.")
+                .value_name("path")
+                .takes_value(true)
+                .multiple(true)
+                .number_of_values(1),
             Arg::with_name("no-layout-tests")
                 .long("no-layout-tests")
                 .help("Avoid generating layout tests for any type."),
@@ -486,6 +494,13 @@
                 .takes_value(true)
                 .multiple(true)
                 .number_of_values(1),
+            Arg::with_name("must-use-type")
+                .long("must-use-type")
+                .help("Add #[must_use] annotation to types matching <regex>.")
+                .value_name("regex")
+                .takes_value(true)
+                .multiple(true)
+                .number_of_values(1),
             Arg::with_name("enable-function-attribute-detection")
                 .long("enable-function-attribute-detection")
                 .help(
@@ -623,6 +638,12 @@
         }
     }
 
+    if let Some(hidden_files) = matches.values_of("blocklist-file") {
+        for file in hidden_files {
+            builder = builder.blocklist_file(file);
+        }
+    }
+
     if matches.is_present("builtins") {
         builder = builder.emit_builtins();
     }
@@ -710,7 +731,7 @@
 
     if let Some(what_to_generate) = matches.value_of("generate") {
         let mut config = CodegenConfig::empty();
-        for what in what_to_generate.split(",") {
+        for what in what_to_generate.split(',') {
             match what {
                 "functions" => config.insert(CodegenConfig::FUNCTIONS),
                 "types" => config.insert(CodegenConfig::TYPES),
@@ -943,6 +964,12 @@
         }
     }
 
+    if let Some(must_use_type) = matches.values_of("must-use-type") {
+        for regex in must_use_type {
+            builder = builder.must_use_type(regex);
+        }
+    }
+
     if let Some(dynamic_library_name) = matches.value_of("dynamic-loading") {
         builder = builder.dynamic_library_name(dynamic_library_name);
     }