Update source v1.73.0

bug: 303458239
Test: ./build.py --lto thin
Change-Id: I777a957c80ea68780804fa0929cf18b90cab955a
diff --git a/.gitmodules b/.gitmodules
index 6b7160b..f502509 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,34 +1,45 @@
 [submodule "src/doc/nomicon"]
 	path = src/doc/nomicon
 	url = https://github.com/rust-lang/nomicon.git
+	shallow = true
 [submodule "src/tools/cargo"]
 	path = src/tools/cargo
 	url = https://github.com/rust-lang/cargo.git
+	shallow = true
 [submodule "src/doc/reference"]
 	path = src/doc/reference
 	url = https://github.com/rust-lang/reference.git
+	shallow = true
 [submodule "src/doc/book"]
 	path = src/doc/book
 	url = https://github.com/rust-lang/book.git
+	shallow = true
 [submodule "src/doc/rust-by-example"]
 	path = src/doc/rust-by-example
 	url = https://github.com/rust-lang/rust-by-example.git
+	shallow = true
 [submodule "library/stdarch"]
 	path = library/stdarch
 	url = https://github.com/rust-lang/stdarch.git
+	shallow = true
 [submodule "src/doc/rustc-dev-guide"]
 	path = src/doc/rustc-dev-guide
 	url = https://github.com/rust-lang/rustc-dev-guide.git
+	shallow = true
 [submodule "src/doc/edition-guide"]
 	path = src/doc/edition-guide
 	url = https://github.com/rust-lang/edition-guide.git
+	shallow = true
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/16.0-2023-06-05
+	branch = rustc/17.0-2023-09-19
+	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
+	shallow = true
 [submodule "library/backtrace"]
 	path = library/backtrace
 	url = https://github.com/rust-lang/backtrace-rs.git
+	shallow = true
diff --git a/Cargo.lock b/Cargo.lock
index 070518f..266f34e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -35,17 +35,6 @@
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "ahash"
 version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
@@ -163,7 +152,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -173,22 +162,25 @@
 checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
 dependencies = [
  "anstyle",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.71"
+version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+dependencies = [
+ "backtrace",
+]
 
 [[package]]
 name = "ar_archive_writer"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74cfb39880a59e122232cb5fb06b20b4382d58c12fa9747d16f846d38a7b094c"
+checksum = "9792d37ca5173d7e7f4fe453739a0671d0557915a030a383d6b866476bbc3e71"
 dependencies = [
- "object 0.31.1",
+ "object 0.32.0",
 ]
 
 [[package]]
@@ -226,7 +218,7 @@
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -268,6 +260,12 @@
 ]
 
 [[package]]
+name = "base64"
+version = "0.21.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+
+[[package]]
 name = "basic-toml"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -337,6 +335,10 @@
 [[package]]
 name = "build_helper"
 version = "0.1.0"
+dependencies = [
+ "serde",
+ "serde_derive",
+]
 
 [[package]]
 name = "bump-stage0"
@@ -498,7 +500,7 @@
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -509,16 +511,25 @@
 
 [[package]]
 name = "clippy"
-version = "0.1.72"
+version = "0.1.73"
 dependencies = [
  "clippy_lints",
+ "clippy_utils",
+ "derive-new",
  "filetime",
+ "futures",
+ "if_chain",
  "itertools",
+ "parking_lot 0.12.1",
+ "quote",
  "regex",
  "rustc_tools_util",
+ "serde",
+ "syn 2.0.27",
  "tempfile",
  "termize",
  "tester",
+ "tokio",
  "toml 0.7.5",
  "ui_test",
  "walkdir",
@@ -539,7 +550,7 @@
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.72"
+version = "0.1.73"
 dependencies = [
  "arrayvec",
  "cargo_metadata",
@@ -563,26 +574,8 @@
 ]
 
 [[package]]
-name = "clippy_test_deps"
-version = "0.1.0"
-dependencies = [
- "clippy_lints",
- "clippy_utils",
- "derive-new",
- "futures",
- "if_chain",
- "itertools",
- "parking_lot 0.12.1",
- "quote",
- "regex",
- "serde",
- "syn 2.0.8",
- "tokio",
-]
-
-[[package]]
 name = "clippy_utils"
-version = "0.1.72"
+version = "0.1.73"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -646,9 +639,9 @@
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.95"
+version = "0.1.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6866e0f3638013234db3c89ead7a14d278354338e7237257407500009012b23f"
+checksum = "d6c0f24437059853f0fa64afc51f338f93647a3de4cf3358ba1bb4171a199775"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -695,6 +688,16 @@
 ]
 
 [[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
 name = "core-foundation-sys"
 version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -792,7 +795,7 @@
 checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
 dependencies = [
  "nix",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -826,6 +829,41 @@
 ]
 
 [[package]]
+name = "darling"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.27",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.27",
+]
+
+[[package]]
 name = "datafrog"
 version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -833,11 +871,11 @@
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.72"
+version = "0.1.73"
 dependencies = [
  "itertools",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -865,6 +903,18 @@
 ]
 
 [[package]]
+name = "derive_setters"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
+]
+
+[[package]]
 name = "diff"
 version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -938,7 +988,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -995,6 +1045,15 @@
 ]
 
 [[package]]
+name = "encoding_rs"
+version = "0.8.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
 name = "env_logger"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1047,7 +1106,7 @@
 dependencies = [
  "errno-dragonfly",
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1098,9 +1157,9 @@
 
 [[package]]
 name = "fallible-iterator"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
 
 [[package]]
 name = "fastrand"
@@ -1130,7 +1189,7 @@
  "cfg-if",
  "libc",
  "redox_syscall 0.2.16",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1184,6 +1243,21 @@
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
 name = "form_urlencoded"
 version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1209,6 +1283,12 @@
 checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541"
 
 [[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
 name = "futf"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1274,7 +1354,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -1357,17 +1437,6 @@
 
 [[package]]
 name = "gimli"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
-dependencies = [
- "fallible-iterator",
- "indexmap 1.9.3",
- "stable_deref_trait",
-]
-
-[[package]]
-name = "gimli"
 version = "0.27.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
@@ -1379,8 +1448,11 @@
 checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 dependencies = [
  "compiler_builtins",
+ "fallible-iterator",
+ "indexmap 2.0.0",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
+ "stable_deref_trait",
 ]
 
 [[package]]
@@ -1412,6 +1484,25 @@
 ]
 
 [[package]]
+name = "h2"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http",
+ "indexmap 1.9.3",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
 name = "handlebars"
 version = "4.3.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1430,18 +1521,6 @@
 version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-dependencies = [
- "ahash 0.7.6",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-dependencies = [
- "ahash 0.8.3",
-]
 
 [[package]]
 name = "hashbrown"
@@ -1449,6 +1528,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
 dependencies = [
+ "ahash",
  "allocator-api2",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -1472,9 +1552,9 @@
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -1510,6 +1590,49 @@
 ]
 
 [[package]]
+name = "http"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
+
+[[package]]
+name = "httpdate"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+
+[[package]]
+name = "humansize"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
+dependencies = [
+ "libm 0.2.7",
+]
+
+[[package]]
 name = "humantime"
 version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1525,6 +1648,43 @@
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
+name = "hyper"
+version = "0.14.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
+[[package]]
 name = "iana-time-zone"
 version = "0.1.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1613,6 +1773,12 @@
 ]
 
 [[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
 name = "idna"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1727,20 +1893,26 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
 dependencies = [
- "hermit-abi 0.3.1",
+ "hermit-abi 0.3.2",
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
+name = "ipnet"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
+
+[[package]]
 name = "is-terminal"
 version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
 dependencies = [
- "hermit-abi 0.3.1",
- "rustix 0.38.1",
- "windows-sys 0.48.0",
+ "hermit-abi 0.3.2",
+ "rustix 0.38.2",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1882,6 +2054,12 @@
 checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
 
 [[package]]
+name = "libm"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+
+[[package]]
 name = "libz-sys"
 version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2120,12 +2298,23 @@
 ]
 
 [[package]]
-name = "miow"
-version = "0.5.0"
+name = "mio"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
+checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
 dependencies = [
- "windows-sys 0.42.0",
+ "libc",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "miow"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
+dependencies = [
+ "windows-sys",
 ]
 
 [[package]]
@@ -2157,6 +2346,24 @@
 ]
 
 [[package]]
+name = "native-tls"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
 name = "new_debug_unreachable"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2185,6 +2392,15 @@
 ]
 
 [[package]]
+name = "ntapi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
 name = "nu-ansi-term"
 version = "0.46.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2209,7 +2425,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi 0.3.1",
+ "hermit-abi 0.3.2",
  "libc",
 ]
 
@@ -2219,12 +2435,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
 dependencies = [
- "crc32fast",
- "flate2",
- "hashbrown 0.13.2",
- "indexmap 1.9.3",
  "memchr",
- "ruzstd",
 ]
 
 [[package]]
@@ -2234,9 +2445,14 @@
 checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
 dependencies = [
  "compiler_builtins",
+ "crc32fast",
+ "flate2",
+ "hashbrown 0.14.0",
+ "indexmap 2.0.0",
  "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
+ "ruzstd",
 ]
 
 [[package]]
@@ -2265,6 +2481,32 @@
 ]
 
 [[package]]
+name = "openssl"
+version = "0.10.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d"
+dependencies = [
+ "bitflags 1.3.2",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
+]
+
+[[package]]
 name = "openssl-probe"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2283,6 +2525,29 @@
 ]
 
 [[package]]
+name = "opt-dist"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "build_helper",
+ "camino",
+ "env_logger 0.10.0",
+ "fs_extra",
+ "glob",
+ "humansize",
+ "humantime 2.1.0",
+ "log",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sysinfo",
+ "tar",
+ "tempfile",
+ "xz",
+ "zip",
+]
+
+[[package]]
 name = "overload"
 version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2301,7 +2566,7 @@
 checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
 dependencies = [
  "cfg-if",
- "libm",
+ "libm 0.1.4",
 ]
 
 [[package]]
@@ -2426,7 +2691,7 @@
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -2755,10 +3020,46 @@
 ]
 
 [[package]]
+name = "reqwest"
+version = "0.11.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
+[[package]]
 name = "rls"
 version = "2.0.0"
 dependencies = [
- "serde",
  "serde_json",
 ]
 
@@ -2882,7 +3183,9 @@
 
 [[package]]
 name = "rustc_apfloat"
-version = "0.0.0"
+version = "0.2.0+llvm-462a31f5a5ab"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "465187772033a5ee566f69fe008df03628fce549a0899aae76f0a0c2e34696be"
 dependencies = [
  "bitflags 1.3.2",
  "smallvec",
@@ -3053,7 +3356,7 @@
  "cstr",
  "libc",
  "measureme",
- "object 0.31.1",
+ "object 0.32.0",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3089,7 +3392,7 @@
  "itertools",
  "jobserver",
  "libc",
- "object 0.31.1",
+ "object 0.32.0",
  "pathdiff",
  "regex",
  "rustc_arena",
@@ -3114,7 +3417,6 @@
  "rustc_type_ir",
  "serde_json",
  "smallvec",
- "snap",
  "tempfile",
  "thorin-dwp",
  "tracing",
@@ -3161,7 +3463,7 @@
  "libc",
  "measureme",
  "memmap2",
- "parking_lot 0.11.2",
+ "parking_lot 0.12.1",
  "rustc-hash",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -3183,7 +3485,6 @@
 version = "0.0.0"
 dependencies = [
  "rustc_driver_impl",
- "rustix 0.37.11",
 ]
 
 [[package]]
@@ -3236,6 +3537,7 @@
  "rustc_trait_selection",
  "rustc_ty_utils",
  "serde_json",
+ "time",
  "tracing",
  "windows",
 ]
@@ -3269,6 +3571,7 @@
 version = "0.0.0"
 dependencies = [
  "annotate-snippets",
+ "derive_setters",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -3311,6 +3614,7 @@
  "rustc_session",
  "rustc_span",
  "smallvec",
+ "termcolor",
  "thin-vec",
  "tracing",
 ]
@@ -3332,7 +3636,7 @@
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
  "unic-langid",
 ]
 
@@ -3404,6 +3708,7 @@
 version = "0.1.0"
 dependencies = [
  "rustc_ast",
+ "rustc_attr",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
@@ -3479,7 +3784,6 @@
 name = "rustc_interface"
 version = "0.0.0"
 dependencies = [
- "atty",
  "libloading",
  "rustc-rayon",
  "rustc-rayon-core",
@@ -3495,6 +3799,7 @@
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
+ "rustc_feature",
  "rustc_fluent_macro",
  "rustc_fs_util",
  "rustc_hir",
@@ -3531,7 +3836,7 @@
 version = "0.1.0"
 dependencies = [
  "expect-test",
- "unic-emoji-char",
+ "unicode-properties",
  "unicode-xid",
 ]
 
@@ -3601,7 +3906,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
  "synstructure 0.13.0",
 ]
 
@@ -3736,6 +4041,7 @@
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
+ "rustc_mir_build",
  "rustc_mir_dataflow",
  "rustc_serialize",
  "rustc_session",
@@ -3880,7 +4186,7 @@
 name = "rustc_query_system"
 version = "0.0.0"
 dependencies = [
- "parking_lot 0.11.2",
+ "parking_lot 0.12.1",
  "rustc-rayon-core",
  "rustc_ast",
  "rustc_data_structures",
@@ -3943,7 +4249,6 @@
 name = "rustc_session"
 version = "0.0.0"
 dependencies = [
- "atty",
  "bitflags 1.3.2",
  "getopts",
  "libc",
@@ -3972,6 +4277,7 @@
  "rustc_hir",
  "rustc_middle",
  "rustc_span",
+ "rustc_target",
  "scoped-tls",
  "tracing",
 ]
@@ -4020,7 +4326,7 @@
 version = "0.0.0"
 dependencies = [
  "bitflags 1.3.2",
- "object 0.31.1",
+ "object 0.32.0",
  "rustc_abi",
  "rustc_data_structures",
  "rustc_feature",
@@ -4208,7 +4514,7 @@
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -4242,29 +4548,29 @@
 
 [[package]]
 name = "rustix"
-version = "0.37.11"
+version = "0.37.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
+checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c"
 dependencies = [
  "bitflags 1.3.2",
  "errno",
  "io-lifetimes",
  "libc",
  "linux-raw-sys 0.3.8",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.1"
+version = "0.38.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3"
+checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4"
 dependencies = [
  "bitflags 2.3.3",
  "errno",
  "libc",
  "linux-raw-sys 0.4.3",
- "windows-sys 0.48.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4275,12 +4581,12 @@
 
 [[package]]
 name = "ruzstd"
-version = "0.3.1"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe"
+checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc"
 dependencies = [
  "byteorder",
- "thiserror",
+ "thiserror-core",
  "twox-hash",
 ]
 
@@ -4301,11 +4607,11 @@
 
 [[package]]
 name = "schannel"
-version = "0.1.21"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
 dependencies = [
- "windows-sys 0.42.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4321,6 +4627,29 @@
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
+name = "security-framework"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
 name = "self_cell"
 version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4352,7 +4681,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -4377,6 +4706,18 @@
 ]
 
 [[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
 name = "sha1"
 version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4436,9 +4777,9 @@
 
 [[package]]
 name = "smallvec"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
 
 [[package]]
 name = "snap"
@@ -4522,7 +4863,7 @@
  "dlmalloc",
  "fortanix-sgx-abi",
  "hashbrown 0.14.0",
- "hermit-abi 0.3.1",
+ "hermit-abi 0.3.2",
  "libc",
  "miniz_oxide",
  "object 0.32.0",
@@ -4621,9 +4962,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.8"
+version = "2.0.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9"
+checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4650,11 +4991,25 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
  "unicode-xid",
 ]
 
 [[package]]
+name = "sysinfo"
+version = "0.29.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9557d0845b86eea8182f7b10dff120214fb6cd9fd937b6f4917714e546a38695"
+dependencies = [
+ "cfg-if",
+ "core-foundation-sys",
+ "libc",
+ "ntapi",
+ "once_cell",
+ "winapi",
+]
+
+[[package]]
 name = "sysroot"
 version = "0.0.0"
 dependencies = [
@@ -4684,8 +5039,8 @@
  "cfg-if",
  "fastrand",
  "redox_syscall 0.3.5",
- "rustix 0.37.11",
- "windows-sys 0.48.0",
+ "rustix 0.37.22",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4725,8 +5080,8 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
 dependencies = [
- "rustix 0.37.11",
- "windows-sys 0.48.0",
+ "rustix 0.37.22",
+ "windows-sys",
 ]
 
 [[package]]
@@ -4771,33 +5126,53 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.40"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
-name = "thiserror-impl"
-version = "1.0.40"
+name = "thiserror-core"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497"
+dependencies = [
+ "thiserror-core-impl",
+]
+
+[[package]]
+name = "thiserror-core-impl"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
 ]
 
 [[package]]
 name = "thorin-dwp"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98c040e1340b889d4180c64e1d787efa9c32cb1617757e101480b61238b0d927"
+checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
 dependencies = [
- "gimli 0.26.2",
- "hashbrown 0.12.3",
- "object 0.31.1",
+ "gimli 0.28.0",
+ "hashbrown 0.14.0",
+ "object 0.32.0",
  "tracing",
 ]
 
@@ -4840,6 +5215,33 @@
 version = "0.1.0"
 
 [[package]]
+name = "time"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
+dependencies = [
+ "itoa",
+ "serde",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+
+[[package]]
+name = "time-macros"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
+dependencies = [
+ "time-core",
+]
+
+[[package]]
 name = "tinystr"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4873,7 +5275,36 @@
  "autocfg",
  "backtrace",
  "bytes",
+ "libc",
+ "mio",
+ "num_cpus",
  "pin-project-lite",
+ "socket2",
+ "windows-sys",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+ "tracing",
 ]
 
 [[package]]
@@ -4926,6 +5357,12 @@
 checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
 
 [[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
+[[package]]
 name = "tracing"
 version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4945,7 +5382,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
 ]
 
 [[package]]
@@ -5011,6 +5448,12 @@
 ]
 
 [[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+
+[[package]]
 name = "twox-hash"
 version = "1.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5054,9 +5497,9 @@
 
 [[package]]
 name = "ui_test"
-version = "0.11.6"
+version = "0.11.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24a2e70adc9d18b9b4dd80ea57aeec447103c6fbb354a07c080adad451c645e1"
+checksum = "c21899b59f53717dfad29e4f46e5b21a200a1b6888ab86532a07cfc8b48dd78c"
 dependencies = [
  "bstr",
  "cargo-platform",
@@ -5075,38 +5518,6 @@
 ]
 
 [[package]]
-name = "unic-char-property"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
-dependencies = [
- "unic-char-range",
-]
-
-[[package]]
-name = "unic-char-range"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
-
-[[package]]
-name = "unic-common"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
-
-[[package]]
-name = "unic-emoji-char"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d"
-dependencies = [
- "unic-char-property",
- "unic-char-range",
- "unic-ucd-version",
-]
-
-[[package]]
 name = "unic-langid"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5150,15 +5561,6 @@
 ]
 
 [[package]]
-name = "unic-ucd-version"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
-dependencies = [
- "unic-common",
-]
-
-[[package]]
 name = "unicase"
 version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5196,6 +5598,12 @@
 ]
 
 [[package]]
+name = "unicode-properties"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
+
+[[package]]
 name = "unicode-script"
 version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5329,6 +5737,15 @@
 ]
 
 [[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5360,11 +5777,23 @@
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5382,7 +5811,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.8",
+ "syn 2.0.27",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -5394,6 +5823,16 @@
 checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
+name = "web-sys"
+version = "0.3.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5451,21 +5890,6 @@
 
 [[package]]
 name = "windows-sys"
-version = "0.42.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
@@ -5479,13 +5903,13 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
 dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
@@ -5496,84 +5920,42 @@
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
@@ -5588,6 +5970,15 @@
 ]
 
 [[package]]
+name = "winreg"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
 name = "writeable"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5603,6 +5994,15 @@
 ]
 
 [[package]]
+name = "xz"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34"
+dependencies = [
+ "xz2",
+]
+
+[[package]]
 name = "xz2"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5707,3 +6107,15 @@
  "syn 1.0.109",
  "synstructure 0.12.6",
 ]
+
+[[package]]
+name = "zip"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
+dependencies = [
+ "byteorder",
+ "crc32fast",
+ "crossbeam-utils",
+ "flate2",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 20b1c65..d2e84d5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,6 @@
   "src/tools/cargotest",
   "src/tools/clippy",
   "src/tools/clippy/clippy_dev",
-  "src/tools/clippy/clippy_test_deps",
   "src/tools/compiletest",
   "src/tools/error_index_generator",
   "src/tools/linkchecker",
@@ -43,6 +42,7 @@
   "src/tools/suggest-tests",
   "src/tools/generate-windows-sys",
   "src/tools/rustdoc-gui-test",
+  "src/tools/opt-dist",
 ]
 
 exclude = [
diff --git a/RELEASES.md b/RELEASES.md
index 85570c9..7674418 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,4 +1,121 @@
-Version 1.72.1 (2023-09-14)
+Version 1.73.0 (2023-10-05)
+==========================
+
+<a id="1.73.0-Language"></a>
+
+Language
+--------
+
+- [Uplift `clippy::fn_null_check` lint as `useless_ptr_null_checks`.](https://github.com/rust-lang/rust/pull/111717/)
+- [Make `noop_method_call` warn by default.](https://github.com/rust-lang/rust/pull/111916/)
+- [Support interpolated block for `try` and `async` in macros.](https://github.com/rust-lang/rust/pull/112953/)
+- [Make `unconditional_recursion` lint detect recursive drops.](https://github.com/rust-lang/rust/pull/113902/)
+- [Future compatibility warning for some impls being incorrectly considered not overlapping.](https://github.com/rust-lang/rust/pull/114023/)
+ - [The `invalid_reference_casting` lint is now **deny-by-default** (instead of allow-by-default)](https://github.com/rust-lang/rust/pull/112431)
+
+<a id="1.73.0-Compiler"></a>
+
+Compiler
+--------
+
+- [Write version information in a `.comment` section like GCC/Clang.](https://github.com/rust-lang/rust/pull/97550/)
+- [Add documentation on v0 symbol mangling.](https://github.com/rust-lang/rust/pull/97571/)
+- [Stabilize `extern "thiscall"` and `"thiscall-unwind"` ABIs.](https://github.com/rust-lang/rust/pull/114562/)
+- [Only check outlives goals on impl compared to trait.](https://github.com/rust-lang/rust/pull/109356/)
+- [Infer type in irrefutable slice patterns with fixed length as array.](https://github.com/rust-lang/rust/pull/113199/)
+- [Discard default auto trait impls if explicit ones exist.](https://github.com/rust-lang/rust/pull/113312/)
+- Add several new tier 3 targets:
+    - [`aarch64-unknown-teeos`](https://github.com/rust-lang/rust/pull/113480/)
+    - [`csky-unknown-linux-gnuabiv2`](https://github.com/rust-lang/rust/pull/113658/)
+    - [`riscv64-linux-android`](https://github.com/rust-lang/rust/pull/112858/)
+    - [`riscv64gc-unknown-hermit`](https://github.com/rust-lang/rust/pull/114004/)
+    - [`x86_64-unikraft-linux-musl`](https://github.com/rust-lang/rust/pull/113411/)
+    - [`x86_64-unknown-linux-ohos`](https://github.com/rust-lang/rust/pull/113061/)
+- [Add `wasm32-wasi-preview1-threads` as a tier 2 target.](https://github.com/rust-lang/rust/pull/112922/)
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+<a id="1.73.0-Libraries"></a>
+
+Libraries
+---------
+
+- [Add `Read`, `Write` and `Seek` impls for `Arc<File>`.](https://github.com/rust-lang/rust/pull/94748/)
+- [Merge functionality of `io::Sink` into `io::Empty`.](https://github.com/rust-lang/rust/pull/98154/)
+- [Implement `RefUnwindSafe` for `Backtrace`](https://github.com/rust-lang/rust/pull/100455/)
+- [Make `ExitStatus` implement `Default`](https://github.com/rust-lang/rust/pull/106425/)
+- [`impl SliceIndex<str> for (Bound<usize>, Bound<usize>)`](https://github.com/rust-lang/rust/pull/111081/)
+- [Change default panic handler message format.](https://github.com/rust-lang/rust/pull/112849/)
+- [Cleaner `assert_eq!` & `assert_ne!` panic messages.](https://github.com/rust-lang/rust/pull/111071/)
+- [Correct the (deprecated) Android `stat` struct definitions.](https://github.com/rust-lang/rust/pull/113130/)
+
+<a id="1.73.0-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [Unsigned `{integer}::div_ceil`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.div_ceil)
+- [Unsigned `{integer}::next_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.next_multiple_of)
+- [Unsigned `{integer}::checked_next_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.checked_next_multiple_of)
+- [`std::ffi::FromBytesUntilNulError`](https://doc.rust-lang.org/stable/std/ffi/struct.FromBytesUntilNulError.html)
+- [`std::os::unix::fs::chown`](https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chown.html)
+- [`std::os::unix::fs::fchown`](https://doc.rust-lang.org/stable/std/os/unix/fs/fn.fchown.html)
+- [`std::os::unix::fs::lfchown`](https://doc.rust-lang.org/stable/std/os/unix/fs/fn.lchown.html)
+- [`LocalKey::<Cell<T>>::get`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.get)
+- [`LocalKey::<Cell<T>>::set`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.set)
+- [`LocalKey::<Cell<T>>::take`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.take)
+- [`LocalKey::<Cell<T>>::replace`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.replace)
+- [`LocalKey::<RefCell<T>>::with_borrow`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.with_borrow)
+- [`LocalKey::<RefCell<T>>::with_borrow_mut`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.with_borrow_mut)
+- [`LocalKey::<RefCell<T>>::set`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.set-1)
+- [`LocalKey::<RefCell<T>>::take`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.take-1)
+- [`LocalKey::<RefCell<T>>::replace`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.replace-1)
+
+These APIs are now stable in const contexts:
+
+- [`rc::Weak::new`](https://doc.rust-lang.org/stable/alloc/rc/struct.Weak.html#method.new)
+- [`sync::Weak::new`](https://doc.rust-lang.org/stable/alloc/sync/struct.Weak.html#method.new)
+- [`NonNull::as_ref`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.as_ref)
+
+<a id="1.73.0-Cargo"></a>
+
+Cargo
+-----
+
+- [Encode URL params correctly for `SourceId` in `Cargo.lock`.](https://github.com/rust-lang/cargo/pull/12280/)
+- [Bail out an error when using `cargo::` in custom build script.](https://github.com/rust-lang/cargo/pull/12332/)
+
+<a id="1.73.0-Misc"></a>
+
+Misc
+----
+
+<a id="1.73.0-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+
+- [Update the minimum external LLVM to 15.](https://github.com/rust-lang/rust/pull/114148/)
+- [Check for non-defining uses of return position `impl Trait`.](https://github.com/rust-lang/rust/pull/112842/)
+
+<a id="1.73.0-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Remove LLVM pointee types, supporting only opaque pointers.](https://github.com/rust-lang/rust/pull/105545/)
+- [Port PGO/LTO/BOLT optimized build pipeline to Rust.](https://github.com/rust-lang/rust/pull/112235/)
+- [Replace in-tree `rustc_apfloat` with the new version of the crate.](https://github.com/rust-lang/rust/pull/113843/)
+- [Update to LLVM 17.](https://github.com/rust-lang/rust/pull/114048/)
+- [Add `internal_features` lint for internal unstable features.](https://github.com/rust-lang/rust/pull/108955/)
+- [Mention style for new syntax in tracking issue template.](https://github.com/rust-lang/rust/pull/113586/)
+
+Version 1.72.1 (2023-09-19)
 ===========================
 
 - [Adjust codegen change to improve LLVM codegen](https://github.com/rust-lang/rust/pull/115236)
@@ -20,9 +137,9 @@
 - [expand: Change how `#![cfg(FALSE)]` behaves on crate root](https://github.com/rust-lang/rust/pull/110141/)
 - [Stabilize inline asm for LoongArch64](https://github.com/rust-lang/rust/pull/111235/)
 - [Uplift `clippy::undropped_manually_drops` lint](https://github.com/rust-lang/rust/pull/111530/)
-- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/)
-- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/)
-- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/)
+- [Uplift `clippy::invalid_utf8_in_unchecked` lint](https://github.com/rust-lang/rust/pull/111543/) as `invalid_from_utf8_unchecked` and `invalid_from_utf8`
+- [Uplift `clippy::cast_ref_to_mut` lint](https://github.com/rust-lang/rust/pull/111567/) as `invalid_reference_casting`
+- [Uplift `clippy::cmp_nan` lint](https://github.com/rust-lang/rust/pull/111818/) as `invalid_nan_comparisons`
 - [resolve: Remove artificial import ambiguity errors](https://github.com/rust-lang/rust/pull/112086/)
 - [Don't require associated types with Self: Sized bounds in `dyn Trait` objects](https://github.com/rust-lang/rust/pull/112319/)
 
@@ -75,16 +192,16 @@
 Stabilized APIs
 ---------------
 
-- [`impl<T: Send> Sync for mpsc::Sender<T>`](https://doc.rust-lang.org/nightly/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E)
-- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/nightly/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str)
-- [`String::leak`](https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.leak)
+- [`impl<T: Send> Sync for mpsc::Sender<T>`](https://doc.rust-lang.org/stable/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E)
+- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str)
+- [`String::leak`](https://doc.rust-lang.org/stable/alloc/string/struct.String.html#method.leak)
 
 These APIs are now stable in const contexts:
 
-- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
-- [`CStr::to_bytes`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
-- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
-- [`CStr::to_str`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
+- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
+- [`CStr::to_bytes`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_bytes)
+- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_bytes_with_nul)
+- [`CStr::to_str`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_str)
 
 <a id="1.72.0-Cargo"></a>
 
diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs
index 39cf3e0..8b7d28d 100644
--- a/compiler/rustc/build.rs
+++ b/compiler/rustc/build.rs
@@ -18,7 +18,7 @@
     let mut manifest = env::current_dir().unwrap();
     manifest.push(WINDOWS_MANIFEST_FILE);
 
-    println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
+    println!("cargo:rerun-if-changed={WINDOWS_MANIFEST_FILE}");
     // Embed the Windows application manifest file.
     println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFEST:EMBED");
     println!("cargo:rustc-link-arg-bin=rustc-main=/MANIFESTINPUT:{}", manifest.to_str().unwrap());
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index f6875d8..a8a1a90 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -40,6 +40,8 @@
             largest_niche,
             align,
             size,
+            max_repr_align: None,
+            unadjusted_abi_align: align.abi,
         }
     }
 
@@ -122,6 +124,8 @@
             largest_niche: None,
             align: dl.i8_align,
             size: Size::ZERO,
+            max_repr_align: None,
+            unadjusted_abi_align: dl.i8_align.abi,
         }
     }
 
@@ -256,8 +260,7 @@
                 }
                 _ => assert!(
                     start == Bound::Unbounded && end == Bound::Unbounded,
-                    "nonscalar layout for layout_scalar_valid_range type: {:#?}",
-                    st,
+                    "nonscalar layout for layout_scalar_valid_range type: {st:#?}",
                 ),
             }
 
@@ -289,6 +292,9 @@
             }
 
             let mut align = dl.aggregate_align;
+            let mut max_repr_align = repr.align;
+            let mut unadjusted_abi_align = align.abi;
+
             let mut variant_layouts = variants
                 .iter_enumerated()
                 .map(|(j, v)| {
@@ -296,6 +302,8 @@
                     st.variants = Variants::Single { index: j };
 
                     align = align.max(st.align);
+                    max_repr_align = max_repr_align.max(st.max_repr_align);
+                    unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
 
                     Some(st)
                 })
@@ -422,6 +430,8 @@
                 largest_niche,
                 size,
                 align,
+                max_repr_align,
+                unadjusted_abi_align,
             };
 
             Some(TmpLayout { layout, variants: variant_layouts })
@@ -452,10 +462,13 @@
             min = 0;
             max = 0;
         }
-        assert!(min <= max, "discriminant range is {}...{}", min, max);
+        assert!(min <= max, "discriminant range is {min}...{max}");
         let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
 
         let mut align = dl.aggregate_align;
+        let mut max_repr_align = repr.align;
+        let mut unadjusted_abi_align = align.abi;
+
         let mut size = Size::ZERO;
 
         // We're interested in the smallest alignment, so start large.
@@ -498,6 +511,8 @@
                 }
                 size = cmp::max(size, st.size);
                 align = align.max(st.align);
+                max_repr_align = max_repr_align.max(st.max_repr_align);
+                unadjusted_abi_align = unadjusted_abi_align.max(st.unadjusted_abi_align);
                 Some(st)
             })
             .collect::<Option<IndexVec<VariantIdx, _>>>()?;
@@ -521,8 +536,7 @@
             // space necessary to represent would have to be discarded (or layout is wrong
             // on thinking it needs 16 bits)
             panic!(
-                "layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
-                min_ity, typeck_ity
+                "layout decided on a larger discriminant type ({min_ity:?}) than typeck ({typeck_ity:?})"
             );
             // However, it is fine to make discr type however large (as an optimisation)
             // after this point – we’ll just truncate the value we load in codegen.
@@ -691,6 +705,8 @@
             abi,
             align,
             size,
+            max_repr_align,
+            unadjusted_abi_align,
         };
 
         let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
@@ -730,10 +746,7 @@
         let dl = self.current_data_layout();
         let dl = dl.borrow();
         let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
-
-        if let Some(repr_align) = repr.align {
-            align = align.max(AbiAndPrefAlign::new(repr_align));
-        }
+        let mut max_repr_align = repr.align;
 
         // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
         // disabled, we can use that common ABI for the union as a whole.
@@ -748,9 +761,12 @@
         let mut size = Size::ZERO;
         let only_variant = &variants[FIRST_VARIANT];
         for field in only_variant {
-            assert!(field.0.is_sized());
+            if field.0.is_unsized() {
+                self.delay_bug("unsized field in union".to_string());
+            }
 
             align = align.max(field.align());
+            max_repr_align = max_repr_align.max(field.max_repr_align());
             size = cmp::max(size, field.size());
 
             if field.0.is_zst() {
@@ -787,6 +803,14 @@
         if let Some(pack) = repr.pack {
             align = align.min(AbiAndPrefAlign::new(pack));
         }
+        // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
+        // See documentation on `LayoutS::unadjusted_abi_align`.
+        let unadjusted_abi_align = align.abi;
+        if let Some(repr_align) = repr.align {
+            align = align.max(AbiAndPrefAlign::new(repr_align));
+        }
+        // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
+        let align = align;
 
         // If all non-ZST fields have the same ABI, we may forward that ABI
         // for the union as a whole, unless otherwise inhibited.
@@ -809,6 +833,8 @@
             largest_niche: None,
             align,
             size: size.align_to(align.abi),
+            max_repr_align,
+            unadjusted_abi_align,
         })
     }
 }
@@ -829,6 +855,7 @@
 ) -> Option<LayoutS> {
     let pack = repr.pack;
     let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+    let mut max_repr_align = repr.align;
     let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
     let optimize = !repr.inhibit_struct_field_reordering_opt();
     if optimize && fields.len() > 1 {
@@ -997,6 +1024,7 @@
         };
         offset = offset.align_to(field_align.abi);
         align = align.max(field_align);
+        max_repr_align = max_repr_align.max(field.max_repr_align());
 
         debug!("univariant offset: {:?} field: {:#?}", offset, field);
         offsets[i] = offset;
@@ -1018,9 +1046,16 @@
 
         offset = offset.checked_add(field.size(), dl)?;
     }
+
+    // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
+    // See documentation on `LayoutS::unadjusted_abi_align`.
+    let unadjusted_abi_align = align.abi;
     if let Some(repr_align) = repr.align {
         align = align.max(AbiAndPrefAlign::new(repr_align));
     }
+    // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate.
+    let align = align;
+
     debug!("univariant min_size: {:?}", offset);
     let min_size = offset;
     // As stated above, inverse_memory_index holds field indices by increasing offset.
@@ -1036,6 +1071,7 @@
         inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
     };
     let size = min_size.align_to(align.abi);
+    let mut layout_of_single_non_zst_field = None;
     let mut abi = Abi::Aggregate { sized };
     // Unpack newtype ABIs and find scalar pairs.
     if sized && size.bytes() > 0 {
@@ -1045,6 +1081,8 @@
         match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
             // We have exactly one non-ZST field.
             (Some((i, field)), None, None) => {
+                layout_of_single_non_zst_field = Some(field);
+
                 // Field fills the struct and it has a scalar or scalar pair ABI.
                 if offsets[i].bytes() == 0 && align.abi == field.align().abi && size == field.size()
                 {
@@ -1102,6 +1140,19 @@
     if fields.iter().any(|f| f.abi().is_uninhabited()) {
         abi = Abi::Uninhabited;
     }
+
+    let unadjusted_abi_align = if repr.transparent() {
+        match layout_of_single_non_zst_field {
+            Some(l) => l.unadjusted_abi_align(),
+            None => {
+                // `repr(transparent)` with all ZST fields.
+                align.abi
+            }
+        }
+    } else {
+        unadjusted_abi_align
+    };
+
     Some(LayoutS {
         variants: Variants::Single { index: FIRST_VARIANT },
         fields: FieldsShape::Arbitrary { offsets, memory_index },
@@ -1109,6 +1160,8 @@
         largest_niche,
         align,
         size,
+        max_repr_align,
+        unadjusted_abi_align,
     })
 }
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index e1b9987..12dd154 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1,4 +1,5 @@
 #![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
+#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
 
 use std::fmt;
 #[cfg(feature = "nightly")]
@@ -332,7 +333,7 @@
             16 => 1 << 15,
             32 => 1 << 31,
             64 => 1 << 47,
-            bits => panic!("obj_size_bound: unknown pointer bit size {}", bits),
+            bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
         }
     }
 
@@ -342,7 +343,7 @@
             16 => I16,
             32 => I32,
             64 => I64,
-            bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits),
+            bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
         }
     }
 
@@ -399,7 +400,7 @@
         match s {
             "little" => Ok(Self::Little),
             "big" => Ok(Self::Big),
-            _ => Err(format!(r#"unknown endian: "{}""#, s)),
+            _ => Err(format!(r#"unknown endian: "{s}""#)),
         }
     }
 }
@@ -456,7 +457,7 @@
     pub fn bits(self) -> u64 {
         #[cold]
         fn overflow(bytes: u64) -> ! {
-            panic!("Size::bits: {} bytes in bits doesn't fit in u64", bytes)
+            panic!("Size::bits: {bytes} bytes in bits doesn't fit in u64")
         }
 
         self.bytes().checked_mul(8).unwrap_or_else(|| overflow(self.bytes()))
@@ -1179,17 +1180,12 @@
                 unreachable!("FieldsShape::offset: `Primitive`s have no fields")
             }
             FieldsShape::Union(count) => {
-                assert!(
-                    i < count.get(),
-                    "tried to access field {} of union with {} fields",
-                    i,
-                    count
-                );
+                assert!(i < count.get(), "tried to access field {i} of union with {count} fields");
                 Size::ZERO
             }
             FieldsShape::Array { stride, count } => {
                 let i = u64::try_from(i).unwrap();
-                assert!(i < count);
+                assert!(i < count, "tried to access field {i} of array with {count} fields");
                 stride * i
             }
             FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)],
@@ -1294,7 +1290,7 @@
                 Primitive::Int(_, signed) => signed,
                 _ => false,
             },
-            _ => panic!("`is_signed` on non-scalar ABI {:?}", self),
+            _ => panic!("`is_signed` on non-scalar ABI {self:?}"),
         }
     }
 
@@ -1345,7 +1341,6 @@
 
     /// Discard validity range information and allow undef.
     pub fn to_union(&self) -> Self {
-        assert!(self.is_sized());
         match *self {
             Abi::Scalar(s) => Abi::Scalar(s.to_union()),
             Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
@@ -1531,6 +1526,16 @@
 
     pub align: AbiAndPrefAlign,
     pub size: Size,
+
+    /// The largest alignment explicitly requested with `repr(align)` on this type or any field.
+    /// Only used on i686-windows, where the argument passing ABI is different when alignment is
+    /// requested, even if the requested alignment is equal to the natural alignment.
+    pub max_repr_align: Option<Align>,
+
+    /// The alignment the type would have, ignoring any `repr(align)` but including `repr(packed)`.
+    /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
+    /// in some cases.
+    pub unadjusted_abi_align: Align,
 }
 
 impl LayoutS {
@@ -1545,6 +1550,8 @@
             largest_niche,
             size,
             align,
+            max_repr_align: None,
+            unadjusted_abi_align: align.abi,
         }
     }
 }
@@ -1554,7 +1561,16 @@
         // This is how `Layout` used to print before it become
         // `Interned<LayoutS>`. We print it like this to avoid having to update
         // expected output in a lot of tests.
-        let LayoutS { size, align, abi, fields, largest_niche, variants } = self;
+        let LayoutS {
+            size,
+            align,
+            abi,
+            fields,
+            largest_niche,
+            variants,
+            max_repr_align,
+            unadjusted_abi_align,
+        } = self;
         f.debug_struct("Layout")
             .field("size", size)
             .field("align", align)
@@ -1562,6 +1578,8 @@
             .field("fields", fields)
             .field("largest_niche", largest_niche)
             .field("variants", variants)
+            .field("max_repr_align", max_repr_align)
+            .field("unadjusted_abi_align", unadjusted_abi_align)
             .finish()
     }
 }
@@ -1602,6 +1620,14 @@
         self.0.0.size
     }
 
+    pub fn max_repr_align(self) -> Option<Align> {
+        self.0.0.max_repr_align
+    }
+
+    pub fn unadjusted_abi_align(self) -> Align {
+        self.0.0.unadjusted_abi_align
+    }
+
     /// Whether the layout is from a type that implements [`std::marker::PointerLike`].
     ///
     /// Currently, that means that the type is pointer-sized, pointer-aligned,
diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml
deleted file mode 100644
index 9830520..0000000
--- a/compiler/rustc_apfloat/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "rustc_apfloat"
-version = "0.0.0"
-edition = "2021"
-
-[dependencies]
-bitflags = "1.2.1"
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs
deleted file mode 100644
index 2286712..0000000
--- a/compiler/rustc_apfloat/src/ieee.rs
+++ /dev/null
@@ -1,2757 +0,0 @@
-use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
-use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd};
-
-use core::cmp::{self, Ordering};
-use core::fmt::{self, Write};
-use core::marker::PhantomData;
-use core::mem;
-use core::ops::Neg;
-use smallvec::{smallvec, SmallVec};
-
-#[must_use]
-pub struct IeeeFloat<S> {
-    /// Absolute significand value (including the integer bit).
-    sig: [Limb; 1],
-
-    /// The signed unbiased exponent of the value.
-    exp: ExpInt,
-
-    /// What kind of floating point number this is.
-    category: Category,
-
-    /// Sign bit of the number.
-    sign: bool,
-
-    marker: PhantomData<S>,
-}
-
-/// Fundamental unit of big integer arithmetic, but also
-/// large to store the largest significands by itself.
-type Limb = u128;
-const LIMB_BITS: usize = 128;
-fn limbs_for_bits(bits: usize) -> usize {
-    (bits + LIMB_BITS - 1) / LIMB_BITS
-}
-
-/// Enum that represents what fraction of the LSB truncated bits of an fp number
-/// represent.
-///
-/// This essentially combines the roles of guard and sticky bits.
-#[must_use]
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Loss {
-    // Example of truncated bits:
-    ExactlyZero,  // 000000
-    LessThanHalf, // 0xxxxx  x's not all zero
-    ExactlyHalf,  // 100000
-    MoreThanHalf, // 1xxxxx  x's not all zero
-}
-
-/// Represents floating point arithmetic semantics.
-pub trait Semantics: Sized {
-    /// Total number of bits in the in-memory format.
-    const BITS: usize;
-
-    /// Number of bits in the significand. This includes the integer bit.
-    const PRECISION: usize;
-
-    /// The largest E such that 2<sup>E</sup> is representable; this matches the
-    /// definition of IEEE 754.
-    const MAX_EXP: ExpInt;
-
-    /// The smallest E such that 2<sup>E</sup> is a normalized number; this
-    /// matches the definition of IEEE 754.
-    const MIN_EXP: ExpInt = -Self::MAX_EXP + 1;
-
-    /// The significand bit that marks NaN as quiet.
-    const QNAN_BIT: usize = Self::PRECISION - 2;
-
-    /// The significand bitpattern to mark a NaN as quiet.
-    /// NOTE: for X87DoubleExtended we need to set two bits instead of 2.
-    const QNAN_SIGNIFICAND: Limb = 1 << Self::QNAN_BIT;
-
-    fn from_bits(bits: u128) -> IeeeFloat<Self> {
-        assert!(Self::BITS > Self::PRECISION);
-
-        let sign = bits & (1 << (Self::BITS - 1));
-        let exponent = (bits & !sign) >> (Self::PRECISION - 1);
-        let mut r = IeeeFloat {
-            sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
-            // Convert the exponent from its bias representation to a signed integer.
-            exp: (exponent as ExpInt) - Self::MAX_EXP,
-            category: Category::Zero,
-            sign: sign != 0,
-            marker: PhantomData,
-        };
-
-        if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Zero;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Infinity;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig != [0] {
-            // Sign, exponent, significand meaningless.
-            r.category = Category::NaN;
-        } else {
-            r.category = Category::Normal;
-            if r.exp == Self::MIN_EXP - 1 {
-                // Denormal.
-                r.exp = Self::MIN_EXP;
-            } else {
-                // Set integer bit.
-                sig::set_bit(&mut r.sig, Self::PRECISION - 1);
-            }
-        }
-
-        r
-    }
-
-    fn to_bits(x: IeeeFloat<Self>) -> u128 {
-        assert!(Self::BITS > Self::PRECISION);
-
-        // Split integer bit from significand.
-        let integer_bit = sig::get_bit(&x.sig, Self::PRECISION - 1);
-        let mut significand = x.sig[0] & ((1 << (Self::PRECISION - 1)) - 1);
-        let exponent = match x.category {
-            Category::Normal => {
-                if x.exp == Self::MIN_EXP && !integer_bit {
-                    // Denormal.
-                    Self::MIN_EXP - 1
-                } else {
-                    x.exp
-                }
-            }
-            Category::Zero => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MIN_EXP - 1
-            }
-            Category::Infinity => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MAX_EXP + 1
-            }
-            Category::NaN => Self::MAX_EXP + 1,
-        };
-
-        // Convert the exponent from a signed integer to its bias representation.
-        let exponent = (exponent + Self::MAX_EXP) as u128;
-
-        ((x.sign as u128) << (Self::BITS - 1)) | (exponent << (Self::PRECISION - 1)) | significand
-    }
-}
-
-impl<S> Copy for IeeeFloat<S> {}
-impl<S> Clone for IeeeFloat<S> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-macro_rules! ieee_semantics {
-    ($($name:ident = $sem:ident($bits:tt : $exp_bits:tt)),*) => {
-        $(pub struct $sem;)*
-        $(pub type $name = IeeeFloat<$sem>;)*
-        $(impl Semantics for $sem {
-            const BITS: usize = $bits;
-            const PRECISION: usize = ($bits - 1 - $exp_bits) + 1;
-            const MAX_EXP: ExpInt = (1 << ($exp_bits - 1)) - 1;
-        })*
-    }
-}
-
-ieee_semantics! {
-    Half = HalfS(16:5),
-    Single = SingleS(32:8),
-    Double = DoubleS(64:11),
-    Quad = QuadS(128:15)
-}
-
-pub struct X87DoubleExtendedS;
-pub type X87DoubleExtended = IeeeFloat<X87DoubleExtendedS>;
-impl Semantics for X87DoubleExtendedS {
-    const BITS: usize = 80;
-    const PRECISION: usize = 64;
-    const MAX_EXP: ExpInt = (1 << (15 - 1)) - 1;
-
-    /// For x87 extended precision, we want to make a NaN, not a
-    /// pseudo-NaN. Maybe we should expose the ability to make
-    /// pseudo-NaNs?
-    const QNAN_SIGNIFICAND: Limb = 0b11 << Self::QNAN_BIT;
-
-    /// Integer bit is explicit in this format. Intel hardware (387 and later)
-    /// does not support these bit patterns:
-    ///  exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity")
-    ///  exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN")
-    ///  exponent = 0, integer bit 1 ("pseudodenormal")
-    ///  exponent != 0 nor all 1's, integer bit 0 ("unnormal")
-    /// At the moment, the first two are treated as NaNs, the second two as Normal.
-    fn from_bits(bits: u128) -> IeeeFloat<Self> {
-        let sign = bits & (1 << (Self::BITS - 1));
-        let exponent = (bits & !sign) >> Self::PRECISION;
-        let mut r = IeeeFloat {
-            sig: [bits & ((1 << (Self::PRECISION - 1)) - 1)],
-            // Convert the exponent from its bias representation to a signed integer.
-            exp: (exponent as ExpInt) - Self::MAX_EXP,
-            category: Category::Zero,
-            sign: sign != 0,
-            marker: PhantomData,
-        };
-
-        if r.exp == Self::MIN_EXP - 1 && r.sig == [0] {
-            // Exponent, significand meaningless.
-            r.category = Category::Zero;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig == [1 << (Self::PRECISION - 1)] {
-            // Exponent, significand meaningless.
-            r.category = Category::Infinity;
-        } else if r.exp == Self::MAX_EXP + 1 && r.sig != [1 << (Self::PRECISION - 1)] {
-            // Sign, exponent, significand meaningless.
-            r.category = Category::NaN;
-        } else {
-            r.category = Category::Normal;
-            if r.exp == Self::MIN_EXP - 1 {
-                // Denormal.
-                r.exp = Self::MIN_EXP;
-            }
-        }
-
-        r
-    }
-
-    fn to_bits(x: IeeeFloat<Self>) -> u128 {
-        // Get integer bit from significand.
-        let integer_bit = sig::get_bit(&x.sig, Self::PRECISION - 1);
-        let mut significand = x.sig[0] & ((1 << Self::PRECISION) - 1);
-        let exponent = match x.category {
-            Category::Normal => {
-                if x.exp == Self::MIN_EXP && !integer_bit {
-                    // Denormal.
-                    Self::MIN_EXP - 1
-                } else {
-                    x.exp
-                }
-            }
-            Category::Zero => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 0;
-                Self::MIN_EXP - 1
-            }
-            Category::Infinity => {
-                // FIXME(eddyb) Maybe we should guarantee an invariant instead?
-                significand = 1 << (Self::PRECISION - 1);
-                Self::MAX_EXP + 1
-            }
-            Category::NaN => Self::MAX_EXP + 1,
-        };
-
-        // Convert the exponent from a signed integer to its bias representation.
-        let exponent = (exponent + Self::MAX_EXP) as u128;
-
-        ((x.sign as u128) << (Self::BITS - 1)) | (exponent << Self::PRECISION) | significand
-    }
-}
-
-float_common_impls!(IeeeFloat<S>);
-
-impl<S: Semantics> PartialEq for IeeeFloat<S> {
-    fn eq(&self, rhs: &Self) -> bool {
-        self.partial_cmp(rhs) == Some(Ordering::Equal)
-    }
-}
-
-impl<S: Semantics> PartialOrd for IeeeFloat<S> {
-    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
-        match (self.category, rhs.category) {
-            (Category::NaN, _) | (_, Category::NaN) => None,
-
-            (Category::Infinity, Category::Infinity) => Some((!self.sign).cmp(&(!rhs.sign))),
-
-            (Category::Zero, Category::Zero) => Some(Ordering::Equal),
-
-            (Category::Infinity, _) | (Category::Normal, Category::Zero) => {
-                Some((!self.sign).cmp(&self.sign))
-            }
-
-            (_, Category::Infinity) | (Category::Zero, Category::Normal) => {
-                Some(rhs.sign.cmp(&(!rhs.sign)))
-            }
-
-            (Category::Normal, Category::Normal) => {
-                // Two normal numbers. Do they have the same sign?
-                Some((!self.sign).cmp(&(!rhs.sign)).then_with(|| {
-                    // Compare absolute values; invert result if negative.
-                    let result = self.cmp_abs_normal(*rhs);
-
-                    if self.sign { result.reverse() } else { result }
-                }))
-            }
-        }
-    }
-}
-
-impl<S> Neg for IeeeFloat<S> {
-    type Output = Self;
-    fn neg(mut self) -> Self {
-        self.sign = !self.sign;
-        self
-    }
-}
-
-/// Prints this value as a decimal string.
-///
-/// \param precision The maximum number of digits of
-///   precision to output. If there are fewer digits available,
-///   zero padding will not be used unless the value is
-///   integral and small enough to be expressed in
-///   precision digits. 0 means to use the natural
-///   precision of the number.
-/// \param width The maximum number of zeros to
-///   consider inserting before falling back to scientific
-///   notation. 0 means to always use scientific notation.
-///
-/// \param alternate Indicate whether to remove the trailing zero in
-///   fraction part or not. Also setting this parameter to true forces
-///   producing of output more similar to default printf behavior.
-///   Specifically the lower e is used as exponent delimiter and exponent
-///   always contains no less than two digits.
-///
-/// Number       precision    width      Result
-/// ------       ---------    -----      ------
-/// 1.01E+4              5        2       10100
-/// 1.01E+4              4        2       1.01E+4
-/// 1.01E+4              5        1       1.01E+4
-/// 1.01E-2              5        2       0.0101
-/// 1.01E-2              4        2       0.0101
-/// 1.01E-2              4        1       1.01E-2
-impl<S: Semantics> fmt::Display for IeeeFloat<S> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let width = f.width().unwrap_or(3);
-        let alternate = f.alternate();
-
-        match self.category {
-            Category::Infinity => {
-                if self.sign {
-                    return f.write_str("-Inf");
-                } else {
-                    return f.write_str("+Inf");
-                }
-            }
-
-            Category::NaN => return f.write_str("NaN"),
-
-            Category::Zero => {
-                if self.sign {
-                    f.write_char('-')?;
-                }
-
-                if width == 0 {
-                    if alternate {
-                        f.write_str("0.0")?;
-                        if let Some(n) = f.precision() {
-                            for _ in 1..n {
-                                f.write_char('0')?;
-                            }
-                        }
-                        f.write_str("e+00")?;
-                    } else {
-                        f.write_str("0.0E+0")?;
-                    }
-                } else {
-                    f.write_char('0')?;
-                }
-                return Ok(());
-            }
-
-            Category::Normal => {}
-        }
-
-        if self.sign {
-            f.write_char('-')?;
-        }
-
-        // We use enough digits so the number can be round-tripped back to an
-        // APFloat. The formula comes from "How to Print Floating-Point Numbers
-        // Accurately" by Steele and White.
-        // FIXME: Using a formula based purely on the precision is conservative;
-        // we can print fewer digits depending on the actual value being printed.
-
-        // precision = 2 + floor(S::PRECISION / lg_2(10))
-        let precision = f.precision().unwrap_or(2 + S::PRECISION * 59 / 196);
-
-        // Decompose the number into an APInt and an exponent.
-        let mut exp = self.exp - (S::PRECISION as ExpInt - 1);
-        let mut sig = vec![self.sig[0]];
-
-        // Ignore trailing binary zeros.
-        let trailing_zeros = sig[0].trailing_zeros();
-        let _: Loss = sig::shift_right(&mut sig, &mut exp, trailing_zeros as usize);
-
-        // Change the exponent from 2^e to 10^e.
-        if exp == 0 {
-            // Nothing to do.
-        } else if exp > 0 {
-            // Just shift left.
-            let shift = exp as usize;
-            sig.resize(limbs_for_bits(S::PRECISION + shift), 0);
-            sig::shift_left(&mut sig, &mut exp, shift);
-        } else {
-            // exp < 0
-            let mut texp = -exp as usize;
-
-            // We transform this using the identity:
-            //   (N)(2^-e) == (N)(5^e)(10^-e)
-
-            // Multiply significand by 5^e.
-            //   N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
-            let mut sig_scratch = vec![];
-            let mut p5 = vec![];
-            let mut p5_scratch = vec![];
-            while texp != 0 {
-                if p5.is_empty() {
-                    p5.push(5);
-                } else {
-                    p5_scratch.resize(p5.len() * 2, 0);
-                    let _: Loss =
-                        sig::mul(&mut p5_scratch, &mut 0, &p5, &p5, p5.len() * 2 * LIMB_BITS);
-                    while p5_scratch.last() == Some(&0) {
-                        p5_scratch.pop();
-                    }
-                    mem::swap(&mut p5, &mut p5_scratch);
-                }
-                if texp & 1 != 0 {
-                    sig_scratch.resize(sig.len() + p5.len(), 0);
-                    let _: Loss = sig::mul(
-                        &mut sig_scratch,
-                        &mut 0,
-                        &sig,
-                        &p5,
-                        (sig.len() + p5.len()) * LIMB_BITS,
-                    );
-                    while sig_scratch.last() == Some(&0) {
-                        sig_scratch.pop();
-                    }
-                    mem::swap(&mut sig, &mut sig_scratch);
-                }
-                texp >>= 1;
-            }
-        }
-
-        // Fill the buffer.
-        let mut buffer = vec![];
-
-        // Ignore digits from the significand until it is no more
-        // precise than is required for the desired precision.
-        // 196/59 is a very slight overestimate of lg_2(10).
-        let required = (precision * 196 + 58) / 59;
-        let mut discard_digits = sig::omsb(&sig).saturating_sub(required) * 59 / 196;
-        let mut in_trail = true;
-        while !sig.is_empty() {
-            // Perform short division by 10 to extract the rightmost digit.
-            // rem <- sig % 10
-            // sig <- sig / 10
-            let mut rem = 0;
-
-            // Use 64-bit division and remainder, with 32-bit chunks from sig.
-            sig::each_chunk(&mut sig, 32, |chunk| {
-                let chunk = chunk as u32;
-                let combined = ((rem as u64) << 32) | (chunk as u64);
-                rem = (combined % 10) as u8;
-                (combined / 10) as u32 as Limb
-            });
-
-            // Reduce the significand to avoid wasting time dividing 0's.
-            while sig.last() == Some(&0) {
-                sig.pop();
-            }
-
-            let digit = rem;
-
-            // Ignore digits we don't need.
-            if discard_digits > 0 {
-                discard_digits -= 1;
-                exp += 1;
-                continue;
-            }
-
-            // Drop trailing zeros.
-            if in_trail && digit == 0 {
-                exp += 1;
-            } else {
-                in_trail = false;
-                buffer.push(b'0' + digit);
-            }
-        }
-
-        assert!(!buffer.is_empty(), "no characters in buffer!");
-
-        // Drop down to precision.
-        // FIXME: don't do more precise calculations above than are required.
-        if buffer.len() > precision {
-            // The most significant figures are the last ones in the buffer.
-            let mut first_sig = buffer.len() - precision;
-
-            // Round.
-            // FIXME: this probably shouldn't use 'round half up'.
-
-            // Rounding down is just a truncation, except we also want to drop
-            // trailing zeros from the new result.
-            if buffer[first_sig - 1] < b'5' {
-                while first_sig < buffer.len() && buffer[first_sig] == b'0' {
-                    first_sig += 1;
-                }
-            } else {
-                // Rounding up requires a decimal add-with-carry. If we continue
-                // the carry, the newly-introduced zeros will just be truncated.
-                for x in &mut buffer[first_sig..] {
-                    if *x == b'9' {
-                        first_sig += 1;
-                    } else {
-                        *x += 1;
-                        break;
-                    }
-                }
-            }
-
-            exp += first_sig as ExpInt;
-            buffer.drain(..first_sig);
-
-            // If we carried through, we have exactly one digit of precision.
-            if buffer.is_empty() {
-                buffer.push(b'1');
-            }
-        }
-
-        let digits = buffer.len();
-
-        // Check whether we should use scientific notation.
-        let scientific = if width == 0 {
-            true
-        } else if exp >= 0 {
-            // 765e3 --> 765000
-            //              ^^^
-            // But we shouldn't make the number look more precise than it is.
-            exp as usize > width || digits + exp as usize > precision
-        } else {
-            // Power of the most significant digit.
-            let msd = exp + (digits - 1) as ExpInt;
-            if msd >= 0 {
-                // 765e-2 == 7.65
-                false
-            } else {
-                // 765e-5 == 0.00765
-                //           ^ ^^
-                -msd as usize > width
-            }
-        };
-
-        // Scientific formatting is pretty straightforward.
-        if scientific {
-            exp += digits as ExpInt - 1;
-
-            f.write_char(buffer[digits - 1] as char)?;
-            f.write_char('.')?;
-            let truncate_zero = !alternate;
-            if digits == 1 && truncate_zero {
-                f.write_char('0')?;
-            } else {
-                for &d in buffer[..digits - 1].iter().rev() {
-                    f.write_char(d as char)?;
-                }
-            }
-            // Fill with zeros up to precision.
-            if !truncate_zero && precision > digits - 1 {
-                for _ in 0..=precision - digits {
-                    f.write_char('0')?;
-                }
-            }
-            // For alternate we use lower 'e'.
-            f.write_char(if alternate { 'e' } else { 'E' })?;
-
-            // Exponent always at least two digits if we do not truncate zeros.
-            if truncate_zero {
-                write!(f, "{:+}", exp)?;
-            } else {
-                write!(f, "{:+03}", exp)?;
-            }
-
-            return Ok(());
-        }
-
-        // Non-scientific, positive exponents.
-        if exp >= 0 {
-            for &d in buffer.iter().rev() {
-                f.write_char(d as char)?;
-            }
-            for _ in 0..exp {
-                f.write_char('0')?;
-            }
-            return Ok(());
-        }
-
-        // Non-scientific, negative exponents.
-        let unit_place = -exp as usize;
-        if unit_place < digits {
-            for &d in buffer[unit_place..].iter().rev() {
-                f.write_char(d as char)?;
-            }
-            f.write_char('.')?;
-            for &d in buffer[..unit_place].iter().rev() {
-                f.write_char(d as char)?;
-            }
-        } else {
-            f.write_str("0.")?;
-            for _ in digits..unit_place {
-                f.write_char('0')?;
-            }
-            for &d in buffer.iter().rev() {
-                f.write_char(d as char)?;
-            }
-        }
-
-        Ok(())
-    }
-}
-
-impl<S: Semantics> fmt::Debug for IeeeFloat<S> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}({:?} | {}{:?} * 2^{})",
-            self,
-            self.category,
-            if self.sign { "-" } else { "+" },
-            self.sig,
-            self.exp
-        )
-    }
-}
-
-impl<S: Semantics> Float for IeeeFloat<S> {
-    const BITS: usize = S::BITS;
-    const PRECISION: usize = S::PRECISION;
-    const MAX_EXP: ExpInt = S::MAX_EXP;
-    const MIN_EXP: ExpInt = S::MIN_EXP;
-
-    const ZERO: Self = IeeeFloat {
-        sig: [0],
-        exp: S::MIN_EXP - 1,
-        category: Category::Zero,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    const INFINITY: Self = IeeeFloat {
-        sig: [0],
-        exp: S::MAX_EXP + 1,
-        category: Category::Infinity,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    // FIXME(eddyb) remove when qnan becomes const fn.
-    const NAN: Self = IeeeFloat {
-        sig: [S::QNAN_SIGNIFICAND],
-        exp: S::MAX_EXP + 1,
-        category: Category::NaN,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    fn qnan(payload: Option<u128>) -> Self {
-        IeeeFloat {
-            sig: [S::QNAN_SIGNIFICAND
-                | payload.map_or(0, |payload| {
-                    // Zero out the excess bits of the significand.
-                    payload & ((1 << S::QNAN_BIT) - 1)
-                })],
-            exp: S::MAX_EXP + 1,
-            category: Category::NaN,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    fn snan(payload: Option<u128>) -> Self {
-        let mut snan = Self::qnan(payload);
-
-        // We always have to clear the QNaN bit to make it an SNaN.
-        sig::clear_bit(&mut snan.sig, S::QNAN_BIT);
-
-        // If there are no bits set in the payload, we have to set
-        // *something* to make it a NaN instead of an infinity;
-        // conventionally, this is the next bit down from the QNaN bit.
-        if snan.sig[0] & !S::QNAN_SIGNIFICAND == 0 {
-            sig::set_bit(&mut snan.sig, S::QNAN_BIT - 1);
-        }
-
-        snan
-    }
-
-    fn largest() -> Self {
-        // We want (in interchange format):
-        //   exponent = 1..10
-        //   significand = 1..1
-        IeeeFloat {
-            sig: [(1 << S::PRECISION) - 1],
-            exp: S::MAX_EXP,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    // We want (in interchange format):
-    //   exponent = 0..0
-    //   significand = 0..01
-    const SMALLEST: Self = IeeeFloat {
-        sig: [1],
-        exp: S::MIN_EXP,
-        category: Category::Normal,
-        sign: false,
-        marker: PhantomData,
-    };
-
-    fn smallest_normalized() -> Self {
-        // We want (in interchange format):
-        //   exponent = 0..0
-        //   significand = 10..0
-        IeeeFloat {
-            sig: [1 << (S::PRECISION - 1)],
-            exp: S::MIN_EXP,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-    }
-
-    fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        let status = match (self.category, rhs.category) {
-            (Category::Infinity, Category::Infinity) => {
-                // Differently signed infinities can only be validly
-                // subtracted.
-                if self.sign != rhs.sign {
-                    self = Self::NAN;
-                    Status::INVALID_OP
-                } else {
-                    Status::OK
-                }
-            }
-
-            // Sign may depend on rounding mode; handled below.
-            (_, Category::Zero) | (Category::NaN, _) | (Category::Infinity, Category::Normal) => {
-                Status::OK
-            }
-
-            (Category::Zero, _) | (_, Category::NaN | Category::Infinity) => {
-                self = rhs;
-                Status::OK
-            }
-
-            // This return code means it was not a simple case.
-            (Category::Normal, Category::Normal) => {
-                let loss = sig::add_or_sub(
-                    &mut self.sig,
-                    &mut self.exp,
-                    &mut self.sign,
-                    &mut [rhs.sig[0]],
-                    rhs.exp,
-                    rhs.sign,
-                );
-                let status;
-                self = unpack!(status=, self.normalize(round, loss));
-
-                // Can only be zero if we lost no fraction.
-                assert!(self.category != Category::Zero || loss == Loss::ExactlyZero);
-
-                status
-            }
-        };
-
-        // If two numbers add (exactly) to zero, IEEE 754 decrees it is a
-        // positive zero unless rounding to minus infinity, except that
-        // adding two like-signed zeroes gives that zero.
-        if self.category == Category::Zero
-            && (rhs.category != Category::Zero || self.sign != rhs.sign)
-        {
-            self.sign = round == Round::TowardNegative;
-        }
-
-        status.and(self)
-    }
-
-    fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.sign ^= rhs.sign;
-
-        match (self.category, rhs.category) {
-            (Category::NaN, _) => {
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (_, Category::NaN) => {
-                self.sign = false;
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, Category::Infinity) | (Category::Infinity, Category::Zero) => {
-                Status::INVALID_OP.and(Self::NAN)
-            }
-
-            (_, Category::Infinity) | (Category::Infinity, _) => {
-                self.category = Category::Infinity;
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, _) | (_, Category::Zero) => {
-                self.category = Category::Zero;
-                Status::OK.and(self)
-            }
-
-            (Category::Normal, Category::Normal) => {
-                self.exp += rhs.exp;
-                let mut wide_sig = [0; 2];
-                let loss =
-                    sig::mul(&mut wide_sig, &mut self.exp, &self.sig, &rhs.sig, S::PRECISION);
-                self.sig = [wide_sig[0]];
-                let mut status;
-                self = unpack!(status=, self.normalize(round, loss));
-                if loss != Loss::ExactlyZero {
-                    status |= Status::INEXACT;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_add_r(mut self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
-        // If and only if all arguments are normal do we need to do an
-        // extended-precision calculation.
-        if !self.is_finite_non_zero() || !multiplicand.is_finite_non_zero() || !addend.is_finite() {
-            let mut status;
-            self = unpack!(status=, self.mul_r(multiplicand, round));
-
-            // FS can only be Status::OK or Status::INVALID_OP. There is no more work
-            // to do in the latter case. The IEEE-754R standard says it is
-            // implementation-defined in this case whether, if ADDEND is a
-            // quiet NaN, we raise invalid op; this implementation does so.
-            //
-            // If we need to do the addition we can do so with normal
-            // precision.
-            if status == Status::OK {
-                self = unpack!(status=, self.add_r(addend, round));
-            }
-            return status.and(self);
-        }
-
-        // Post-multiplication sign, before addition.
-        self.sign ^= multiplicand.sign;
-
-        // Allocate space for twice as many bits as the original significand, plus one
-        // extra bit for the addition to overflow into.
-        assert!(limbs_for_bits(S::PRECISION * 2 + 1) <= 2);
-        let mut wide_sig = sig::widening_mul(self.sig[0], multiplicand.sig[0]);
-
-        let mut loss = Loss::ExactlyZero;
-        let mut omsb = sig::omsb(&wide_sig);
-        self.exp += multiplicand.exp;
-
-        // Assume the operands involved in the multiplication are single-precision
-        // FP, and the two multiplicants are:
-        //     lhs = a23 . a22 ... a0 * 2^e1
-        //     rhs = b23 . b22 ... b0 * 2^e2
-        // the result of multiplication is:
-        //     lhs = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
-        // Note that there are three significant bits at the left-hand side of the
-        // radix point: two for the multiplication, and an overflow bit for the
-        // addition (that will always be zero at this point). Move the radix point
-        // toward left by two bits, and adjust exponent accordingly.
-        self.exp += 2;
-
-        if addend.is_non_zero() {
-            // Normalize our MSB to one below the top bit to allow for overflow.
-            let ext_precision = 2 * S::PRECISION + 1;
-            if omsb != ext_precision - 1 {
-                assert!(ext_precision > omsb);
-                sig::shift_left(&mut wide_sig, &mut self.exp, (ext_precision - 1) - omsb);
-            }
-
-            // The intermediate result of the multiplication has "2 * S::PRECISION"
-            // significant bit; adjust the addend to be consistent with mul result.
-            let mut ext_addend_sig = [addend.sig[0], 0];
-
-            // Extend the addend significand to ext_precision - 1. This guarantees
-            // that the high bit of the significand is zero (same as wide_sig),
-            // so the addition will overflow (if it does overflow at all) into the top bit.
-            sig::shift_left(&mut ext_addend_sig, &mut 0, ext_precision - 1 - S::PRECISION);
-            loss = sig::add_or_sub(
-                &mut wide_sig,
-                &mut self.exp,
-                &mut self.sign,
-                &mut ext_addend_sig,
-                addend.exp + 1,
-                addend.sign,
-            );
-
-            omsb = sig::omsb(&wide_sig);
-        }
-
-        // Convert the result having "2 * S::PRECISION" significant-bits back to the one
-        // having "S::PRECISION" significant-bits. First, move the radix point from
-        // position "2*S::PRECISION - 1" to "S::PRECISION - 1". The exponent need to be
-        // adjusted by "2*S::PRECISION - 1" - "S::PRECISION - 1" = "S::PRECISION".
-        self.exp -= S::PRECISION as ExpInt + 1;
-
-        // In case MSB resides at the left-hand side of radix point, shift the
-        // mantissa right by some amount to make sure the MSB reside right before
-        // the radix point (i.e., "MSB . rest-significant-bits").
-        if omsb > S::PRECISION {
-            let bits = omsb - S::PRECISION;
-            loss = sig::shift_right(&mut wide_sig, &mut self.exp, bits).combine(loss);
-        }
-
-        self.sig[0] = wide_sig[0];
-
-        let mut status;
-        self = unpack!(status=, self.normalize(round, loss));
-        if loss != Loss::ExactlyZero {
-            status |= Status::INEXACT;
-        }
-
-        // If two numbers add (exactly) to zero, IEEE 754 decrees it is a
-        // positive zero unless rounding to minus infinity, except that
-        // adding two like-signed zeroes gives that zero.
-        if self.category == Category::Zero
-            && !status.intersects(Status::UNDERFLOW)
-            && self.sign != addend.sign
-        {
-            self.sign = round == Round::TowardNegative;
-        }
-
-        status.and(self)
-    }
-
-    fn div_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.sign ^= rhs.sign;
-
-        match (self.category, rhs.category) {
-            (Category::NaN, _) => {
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (_, Category::NaN) => {
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                self.sign = false;
-                Status::OK.and(self)
-            }
-
-            (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {
-                Status::INVALID_OP.and(Self::NAN)
-            }
-
-            (Category::Infinity | Category::Zero, _) => Status::OK.and(self),
-
-            (Category::Normal, Category::Infinity) => {
-                self.category = Category::Zero;
-                Status::OK.and(self)
-            }
-
-            (Category::Normal, Category::Zero) => {
-                self.category = Category::Infinity;
-                Status::DIV_BY_ZERO.and(self)
-            }
-
-            (Category::Normal, Category::Normal) => {
-                self.exp -= rhs.exp;
-                let dividend = self.sig[0];
-                let loss = sig::div(
-                    &mut self.sig,
-                    &mut self.exp,
-                    &mut [dividend],
-                    &mut [rhs.sig[0]],
-                    S::PRECISION,
-                );
-                let mut status;
-                self = unpack!(status=, self.normalize(round, loss));
-                if loss != Loss::ExactlyZero {
-                    status |= Status::INEXACT;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn c_fmod(mut self, rhs: Self) -> StatusAnd<Self> {
-        match (self.category, rhs.category) {
-            (Category::NaN, _)
-            | (Category::Zero, Category::Infinity | Category::Normal)
-            | (Category::Normal, Category::Infinity) => Status::OK.and(self),
-
-            (_, Category::NaN) => {
-                self.sign = false;
-                self.category = Category::NaN;
-                self.sig = rhs.sig;
-                Status::OK.and(self)
-            }
-
-            (Category::Infinity, _) | (_, Category::Zero) => Status::INVALID_OP.and(Self::NAN),
-
-            (Category::Normal, Category::Normal) => {
-                while self.is_finite_non_zero()
-                    && rhs.is_finite_non_zero()
-                    && self.cmp_abs_normal(rhs) != Ordering::Less
-                {
-                    let mut v = rhs.scalbn(self.ilogb() - rhs.ilogb());
-                    if self.cmp_abs_normal(v) == Ordering::Less {
-                        v = v.scalbn(-1);
-                    }
-                    v.sign = self.sign;
-
-                    let status;
-                    self = unpack!(status=, self - v);
-                    assert_eq!(status, Status::OK);
-                }
-                Status::OK.and(self)
-            }
-        }
-    }
-
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
-        // If the exponent is large enough, we know that this value is already
-        // integral, and the arithmetic below would potentially cause it to saturate
-        // to +/-Inf. Bail out early instead.
-        if self.is_finite_non_zero() && self.exp + 1 >= S::PRECISION as ExpInt {
-            return Status::OK.and(self);
-        }
-
-        // The algorithm here is quite simple: we add 2^(p-1), where p is the
-        // precision of our format, and then subtract it back off again. The choice
-        // of rounding modes for the addition/subtraction determines the rounding mode
-        // for our integral rounding as well.
-        // NOTE: When the input value is negative, we do subtraction followed by
-        // addition instead.
-        assert!(S::PRECISION <= 128);
-        let mut status;
-        let magic_const = unpack!(status=, Self::from_u128(1 << (S::PRECISION - 1)));
-        let magic_const = magic_const.copy_sign(self);
-
-        if status != Status::OK {
-            return status.and(self);
-        }
-
-        let mut r = self;
-        r = unpack!(status=, r.add_r(magic_const, round));
-        if status != Status::OK && status != Status::INEXACT {
-            return status.and(self);
-        }
-
-        // Restore the input sign to handle 0.0/-0.0 cases correctly.
-        r.sub_r(magic_const, round).map(|r| r.copy_sign(self))
-    }
-
-    fn next_up(mut self) -> StatusAnd<Self> {
-        // Compute nextUp(x), handling each float category separately.
-        match self.category {
-            Category::Infinity => {
-                if self.sign {
-                    // nextUp(-inf) = -largest
-                    Status::OK.and(-Self::largest())
-                } else {
-                    // nextUp(+inf) = +inf
-                    Status::OK.and(self)
-                }
-            }
-            Category::NaN => {
-                // IEEE-754R 2008 6.2 Par 2: nextUp(sNaN) = qNaN. Set Invalid flag.
-                // IEEE-754R 2008 6.2: nextUp(qNaN) = qNaN. Must be identity so we do not
-                //                     change the payload.
-                if self.is_signaling() {
-                    // For consistency, propagate the sign of the sNaN to the qNaN.
-                    Status::INVALID_OP.and(Self::NAN.copy_sign(self))
-                } else {
-                    Status::OK.and(self)
-                }
-            }
-            Category::Zero => {
-                // nextUp(pm 0) = +smallest
-                Status::OK.and(Self::SMALLEST)
-            }
-            Category::Normal => {
-                // nextUp(-smallest) = -0
-                if self.is_smallest() && self.sign {
-                    return Status::OK.and(-Self::ZERO);
-                }
-
-                // nextUp(largest) == INFINITY
-                if self.is_largest() && !self.sign {
-                    return Status::OK.and(Self::INFINITY);
-                }
-
-                // Excluding the integral bit. This allows us to test for binade boundaries.
-                let sig_mask = (1 << (S::PRECISION - 1)) - 1;
-
-                // nextUp(normal) == normal + inc.
-                if self.sign {
-                    // If we are negative, we need to decrement the significand.
-
-                    // We only cross a binade boundary that requires adjusting the exponent
-                    // if:
-                    //   1. exponent != S::MIN_EXP. This implies we are not in the
-                    //   smallest binade or are dealing with denormals.
-                    //   2. Our significand excluding the integral bit is all zeros.
-                    let crossing_binade_boundary =
-                        self.exp != S::MIN_EXP && self.sig[0] & sig_mask == 0;
-
-                    // Decrement the significand.
-                    //
-                    // We always do this since:
-                    //   1. If we are dealing with a non-binade decrement, by definition we
-                    //   just decrement the significand.
-                    //   2. If we are dealing with a normal -> normal binade decrement, since
-                    //   we have an explicit integral bit the fact that all bits but the
-                    //   integral bit are zero implies that subtracting one will yield a
-                    //   significand with 0 integral bit and 1 in all other spots. Thus we
-                    //   must just adjust the exponent and set the integral bit to 1.
-                    //   3. If we are dealing with a normal -> denormal binade decrement,
-                    //   since we set the integral bit to 0 when we represent denormals, we
-                    //   just decrement the significand.
-                    sig::decrement(&mut self.sig);
-
-                    if crossing_binade_boundary {
-                        // Our result is a normal number. Do the following:
-                        // 1. Set the integral bit to 1.
-                        // 2. Decrement the exponent.
-                        sig::set_bit(&mut self.sig, S::PRECISION - 1);
-                        self.exp -= 1;
-                    }
-                } else {
-                    // If we are positive, we need to increment the significand.
-
-                    // We only cross a binade boundary that requires adjusting the exponent if
-                    // the input is not a denormal and all of said input's significand bits
-                    // are set. If all of said conditions are true: clear the significand, set
-                    // the integral bit to 1, and increment the exponent. If we have a
-                    // denormal always increment since moving denormals and the numbers in the
-                    // smallest normal binade have the same exponent in our representation.
-                    let crossing_binade_boundary =
-                        !self.is_denormal() && self.sig[0] & sig_mask == sig_mask;
-
-                    if crossing_binade_boundary {
-                        self.sig = [0];
-                        sig::set_bit(&mut self.sig, S::PRECISION - 1);
-                        assert_ne!(
-                            self.exp,
-                            S::MAX_EXP,
-                            "We can not increment an exponent beyond the MAX_EXP \
-                             allowed by the given floating point semantics."
-                        );
-                        self.exp += 1;
-                    } else {
-                        sig::increment(&mut self.sig);
-                    }
-                }
-                Status::OK.and(self)
-            }
-        }
-    }
-
-    fn from_bits(input: u128) -> Self {
-        // Dispatch to semantics.
-        S::from_bits(input)
-    }
-
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
-        IeeeFloat {
-            sig: [input],
-            exp: S::PRECISION as ExpInt - 1,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        }
-        .normalize(round, Loss::ExactlyZero)
-    }
-
-    fn from_str_r(mut s: &str, mut round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        if s.is_empty() {
-            return Err(ParseError("Invalid string length"));
-        }
-
-        // Handle special cases.
-        match s {
-            "inf" | "INFINITY" => return Ok(Status::OK.and(Self::INFINITY)),
-            "-inf" | "-INFINITY" => return Ok(Status::OK.and(-Self::INFINITY)),
-            "nan" | "NaN" => return Ok(Status::OK.and(Self::NAN)),
-            "-nan" | "-NaN" => return Ok(Status::OK.and(-Self::NAN)),
-            _ => {}
-        }
-
-        // Handle a leading minus sign.
-        let minus = s.starts_with('-');
-        if minus || s.starts_with('+') {
-            s = &s[1..];
-            if s.is_empty() {
-                return Err(ParseError("String has no digits"));
-            }
-        }
-
-        // Adjust the rounding mode for the absolute value below.
-        if minus {
-            round = -round;
-        }
-
-        let r = if s.starts_with("0x") || s.starts_with("0X") {
-            s = &s[2..];
-            if s.is_empty() {
-                return Err(ParseError("Invalid string"));
-            }
-            Self::from_hexadecimal_string(s, round)?
-        } else {
-            Self::from_decimal_string(s, round)?
-        };
-
-        Ok(r.map(|r| if minus { -r } else { r }))
-    }
-
-    fn to_bits(self) -> u128 {
-        // Dispatch to semantics.
-        S::to_bits(self)
-    }
-
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
-        // The result of trying to convert a number too large.
-        let overflow = if self.sign {
-            // Negative numbers cannot be represented as unsigned.
-            0
-        } else {
-            // Largest unsigned integer of the given width.
-            !0 >> (128 - width)
-        };
-
-        *is_exact = false;
-
-        match self.category {
-            Category::NaN => Status::INVALID_OP.and(0),
-
-            Category::Infinity => Status::INVALID_OP.and(overflow),
-
-            Category::Zero => {
-                // Negative zero can't be represented as an int.
-                *is_exact = !self.sign;
-                Status::OK.and(0)
-            }
-
-            Category::Normal => {
-                let mut r = 0;
-
-                // Step 1: place our absolute value, with any fraction truncated, in
-                // the destination.
-                let truncated_bits = if self.exp < 0 {
-                    // Our absolute value is less than one; truncate everything.
-                    // For exponent -1 the integer bit represents .5, look at that.
-                    // For smaller exponents leftmost truncated bit is 0.
-                    S::PRECISION - 1 + (-self.exp) as usize
-                } else {
-                    // We want the most significant (exponent + 1) bits; the rest are
-                    // truncated.
-                    let bits = self.exp as usize + 1;
-
-                    // Hopelessly large in magnitude?
-                    if bits > width {
-                        return Status::INVALID_OP.and(overflow);
-                    }
-
-                    if bits < S::PRECISION {
-                        // We truncate (S::PRECISION - bits) bits.
-                        r = self.sig[0] >> (S::PRECISION - bits);
-                        S::PRECISION - bits
-                    } else {
-                        // We want at least as many bits as are available.
-                        r = self.sig[0] << (bits - S::PRECISION);
-                        0
-                    }
-                };
-
-                // Step 2: work out any lost fraction, and increment the absolute
-                // value if we would round away from zero.
-                let mut loss = Loss::ExactlyZero;
-                if truncated_bits > 0 {
-                    loss = Loss::through_truncation(&self.sig, truncated_bits);
-                    if loss != Loss::ExactlyZero
-                        && self.round_away_from_zero(round, loss, truncated_bits)
-                    {
-                        r = r.wrapping_add(1);
-                        if r == 0 {
-                            return Status::INVALID_OP.and(overflow); // Overflow.
-                        }
-                    }
-                }
-
-                // Step 3: check if we fit in the destination.
-                if r > overflow {
-                    return Status::INVALID_OP.and(overflow);
-                }
-
-                if loss == Loss::ExactlyZero {
-                    *is_exact = true;
-                    Status::OK.and(r)
-                } else {
-                    Status::INEXACT.and(r)
-                }
-            }
-        }
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering {
-        assert!(self.is_finite_non_zero());
-        assert!(rhs.is_finite_non_zero());
-
-        // If exponents are equal, do an unsigned comparison of the significands.
-        self.exp.cmp(&rhs.exp).then_with(|| sig::cmp(&self.sig, &rhs.sig))
-    }
-
-    fn bitwise_eq(self, rhs: Self) -> bool {
-        if self.category != rhs.category || self.sign != rhs.sign {
-            return false;
-        }
-
-        if self.category == Category::Zero || self.category == Category::Infinity {
-            return true;
-        }
-
-        if self.is_finite_non_zero() && self.exp != rhs.exp {
-            return false;
-        }
-
-        self.sig == rhs.sig
-    }
-
-    fn is_negative(self) -> bool {
-        self.sign
-    }
-
-    fn is_denormal(self) -> bool {
-        self.is_finite_non_zero()
-            && self.exp == S::MIN_EXP
-            && !sig::get_bit(&self.sig, S::PRECISION - 1)
-    }
-
-    fn is_signaling(self) -> bool {
-        // IEEE-754R 2008 6.2.1: A signaling NaN bit string should be encoded with the
-        // first bit of the trailing significand being 0.
-        self.is_nan() && !sig::get_bit(&self.sig, S::QNAN_BIT)
-    }
-
-    fn category(self) -> Category {
-        self.category
-    }
-
-    fn get_exact_inverse(self) -> Option<Self> {
-        // Special floats and denormals have no exact inverse.
-        if !self.is_finite_non_zero() {
-            return None;
-        }
-
-        // Check that the number is a power of two by making sure that only the
-        // integer bit is set in the significand.
-        if self.sig != [1 << (S::PRECISION - 1)] {
-            return None;
-        }
-
-        // Get the inverse.
-        let mut reciprocal = Self::from_u128(1).value;
-        let status;
-        reciprocal = unpack!(status=, reciprocal / self);
-        if status != Status::OK {
-            return None;
-        }
-
-        // Avoid multiplication with a denormal, it is not safe on all platforms and
-        // may be slower than a normal division.
-        if reciprocal.is_denormal() {
-            return None;
-        }
-
-        assert!(reciprocal.is_finite_non_zero());
-        assert_eq!(reciprocal.sig, [1 << (S::PRECISION - 1)]);
-
-        Some(reciprocal)
-    }
-
-    fn ilogb(mut self) -> ExpInt {
-        if self.is_nan() {
-            return IEK_NAN;
-        }
-        if self.is_zero() {
-            return IEK_ZERO;
-        }
-        if self.is_infinite() {
-            return IEK_INF;
-        }
-        if !self.is_denormal() {
-            return self.exp;
-        }
-
-        let sig_bits = (S::PRECISION - 1) as ExpInt;
-        self.exp += sig_bits;
-        self = self.normalize(Round::NearestTiesToEven, Loss::ExactlyZero).value;
-        self.exp - sig_bits
-    }
-
-    fn scalbn_r(mut self, exp: ExpInt, round: Round) -> Self {
-        // If exp is wildly out-of-scale, simply adding it to self.exp will
-        // overflow; clamp it to a safe range before adding, but ensure that the range
-        // is large enough that the clamp does not change the result. The range we
-        // need to support is the difference between the largest possible exponent and
-        // the normalized exponent of half the smallest denormal.
-
-        let sig_bits = (S::PRECISION - 1) as i32;
-        let max_change = S::MAX_EXP as i32 - (S::MIN_EXP as i32 - sig_bits) + 1;
-
-        // Clamp to one past the range ends to let normalize handle overflow.
-        let exp_change = cmp::min(cmp::max(exp as i32, -max_change - 1), max_change);
-        self.exp = self.exp.saturating_add(exp_change as ExpInt);
-        self = self.normalize(round, Loss::ExactlyZero).value;
-        if self.is_nan() {
-            sig::set_bit(&mut self.sig, S::QNAN_BIT);
-        }
-        self
-    }
-
-    fn frexp_r(mut self, exp: &mut ExpInt, round: Round) -> Self {
-        *exp = self.ilogb();
-
-        // Quiet signalling nans.
-        if *exp == IEK_NAN {
-            sig::set_bit(&mut self.sig, S::QNAN_BIT);
-            return self;
-        }
-
-        if *exp == IEK_INF {
-            return self;
-        }
-
-        // 1 is added because frexp is defined to return a normalized fraction in
-        // +/-[0.5, 1.0), rather than the usual +/-[1.0, 2.0).
-        if *exp == IEK_ZERO {
-            *exp = 0;
-        } else {
-            *exp += 1;
-        }
-        self.scalbn_r(-*exp, round)
-    }
-}
-
-impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
-    fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<IeeeFloat<T>> {
-        let mut r = IeeeFloat {
-            sig: self.sig,
-            exp: self.exp,
-            category: self.category,
-            sign: self.sign,
-            marker: PhantomData,
-        };
-
-        // x86 has some unusual NaNs which cannot be represented in any other
-        // format; note them here.
-        fn is_x87_double_extended<S: Semantics>() -> bool {
-            S::QNAN_SIGNIFICAND == X87DoubleExtendedS::QNAN_SIGNIFICAND
-        }
-        let x87_special_nan = is_x87_double_extended::<S>()
-            && !is_x87_double_extended::<T>()
-            && r.category == Category::NaN
-            && (r.sig[0] & S::QNAN_SIGNIFICAND) != S::QNAN_SIGNIFICAND;
-
-        // If this is a truncation of a denormal number, and the target semantics
-        // has larger exponent range than the source semantics (this can happen
-        // when truncating from PowerPC double-double to double format), the
-        // right shift could lose result mantissa bits. Adjust exponent instead
-        // of performing excessive shift.
-        let mut shift = T::PRECISION as ExpInt - S::PRECISION as ExpInt;
-        if shift < 0 && r.is_finite_non_zero() {
-            let mut exp_change = sig::omsb(&r.sig) as ExpInt - S::PRECISION as ExpInt;
-            if r.exp + exp_change < T::MIN_EXP {
-                exp_change = T::MIN_EXP - r.exp;
-            }
-            if exp_change < shift {
-                exp_change = shift;
-            }
-            if exp_change < 0 {
-                shift -= exp_change;
-                r.exp += exp_change;
-            }
-        }
-
-        // If this is a truncation, perform the shift.
-        let loss = if shift < 0 && (r.is_finite_non_zero() || r.category == Category::NaN) {
-            sig::shift_right(&mut r.sig, &mut 0, -shift as usize)
-        } else {
-            Loss::ExactlyZero
-        };
-
-        // If this is an extension, perform the shift.
-        if shift > 0 && (r.is_finite_non_zero() || r.category == Category::NaN) {
-            sig::shift_left(&mut r.sig, &mut 0, shift as usize);
-        }
-
-        let status;
-        if r.is_finite_non_zero() {
-            r = unpack!(status=, r.normalize(round, loss));
-            *loses_info = status != Status::OK;
-        } else if r.category == Category::NaN {
-            *loses_info = loss != Loss::ExactlyZero || x87_special_nan;
-
-            // For x87 extended precision, we want to make a NaN, not a special NaN if
-            // the input wasn't special either.
-            if !x87_special_nan && is_x87_double_extended::<T>() {
-                sig::set_bit(&mut r.sig, T::PRECISION - 1);
-            }
-
-            // Convert of sNaN creates qNaN and raises an exception (invalid op).
-            // This also guarantees that a sNaN does not become Inf on a truncation
-            // that loses all payload bits.
-            if self.is_signaling() {
-                // Quiet signaling NaN.
-                sig::set_bit(&mut r.sig, T::QNAN_BIT);
-                status = Status::INVALID_OP;
-            } else {
-                status = Status::OK;
-            }
-        } else {
-            *loses_info = false;
-            status = Status::OK;
-        }
-
-        status.and(r)
-    }
-}
-
-impl<S: Semantics> IeeeFloat<S> {
-    /// Handle positive overflow. We either return infinity or
-    /// the largest finite number. For negative overflow,
-    /// negate the `round` argument before calling.
-    fn overflow_result(round: Round) -> StatusAnd<Self> {
-        match round {
-            // Infinity?
-            Round::NearestTiesToEven | Round::NearestTiesToAway | Round::TowardPositive => {
-                (Status::OVERFLOW | Status::INEXACT).and(Self::INFINITY)
-            }
-            // Otherwise we become the largest finite number.
-            Round::TowardNegative | Round::TowardZero => Status::INEXACT.and(Self::largest()),
-        }
-    }
-
-    /// Returns `true` if, when truncating the current number, with `bit` the
-    /// new LSB, with the given lost fraction and rounding mode, the result
-    /// would need to be rounded away from zero (i.e., by increasing the
-    /// signficand). This routine must work for `Category::Zero` of both signs, and
-    /// `Category::Normal` numbers.
-    fn round_away_from_zero(&self, round: Round, loss: Loss, bit: usize) -> bool {
-        // NaNs and infinities should not have lost fractions.
-        assert!(self.is_finite_non_zero() || self.is_zero());
-
-        // Current callers never pass this so we don't handle it.
-        assert_ne!(loss, Loss::ExactlyZero);
-
-        match round {
-            Round::NearestTiesToAway => loss == Loss::ExactlyHalf || loss == Loss::MoreThanHalf,
-            Round::NearestTiesToEven => {
-                if loss == Loss::MoreThanHalf {
-                    return true;
-                }
-
-                // Our zeros don't have a significand to test.
-                if loss == Loss::ExactlyHalf && self.category != Category::Zero {
-                    return sig::get_bit(&self.sig, bit);
-                }
-
-                false
-            }
-            Round::TowardZero => false,
-            Round::TowardPositive => !self.sign,
-            Round::TowardNegative => self.sign,
-        }
-    }
-
-    fn normalize(mut self, round: Round, mut loss: Loss) -> StatusAnd<Self> {
-        if !self.is_finite_non_zero() {
-            return Status::OK.and(self);
-        }
-
-        // Before rounding normalize the exponent of Category::Normal numbers.
-        let mut omsb = sig::omsb(&self.sig);
-
-        if omsb > 0 {
-            // OMSB is numbered from 1. We want to place it in the integer
-            // bit numbered PRECISION if possible, with a compensating change in
-            // the exponent.
-            let mut final_exp = self.exp.saturating_add(omsb as ExpInt - S::PRECISION as ExpInt);
-
-            // If the resulting exponent is too high, overflow according to
-            // the rounding mode.
-            if final_exp > S::MAX_EXP {
-                let round = if self.sign { -round } else { round };
-                return Self::overflow_result(round).map(|r| r.copy_sign(self));
-            }
-
-            // Subnormal numbers have exponent MIN_EXP, and their MSB
-            // is forced based on that.
-            if final_exp < S::MIN_EXP {
-                final_exp = S::MIN_EXP;
-            }
-
-            // Shifting left is easy as we don't lose precision.
-            if final_exp < self.exp {
-                assert_eq!(loss, Loss::ExactlyZero);
-
-                let exp_change = (self.exp - final_exp) as usize;
-                sig::shift_left(&mut self.sig, &mut self.exp, exp_change);
-
-                return Status::OK.and(self);
-            }
-
-            // Shift right and capture any new lost fraction.
-            if final_exp > self.exp {
-                let exp_change = (final_exp - self.exp) as usize;
-                loss = sig::shift_right(&mut self.sig, &mut self.exp, exp_change).combine(loss);
-
-                // Keep OMSB up-to-date.
-                omsb = omsb.saturating_sub(exp_change);
-            }
-        }
-
-        // Now round the number according to round given the lost
-        // fraction.
-
-        // As specified in IEEE 754, since we do not trap we do not report
-        // underflow for exact results.
-        if loss == Loss::ExactlyZero {
-            // Canonicalize zeros.
-            if omsb == 0 {
-                self.category = Category::Zero;
-            }
-
-            return Status::OK.and(self);
-        }
-
-        // Increment the significand if we're rounding away from zero.
-        if self.round_away_from_zero(round, loss, 0) {
-            if omsb == 0 {
-                self.exp = S::MIN_EXP;
-            }
-
-            // We should never overflow.
-            assert_eq!(sig::increment(&mut self.sig), 0);
-            omsb = sig::omsb(&self.sig);
-
-            // Did the significand increment overflow?
-            if omsb == S::PRECISION + 1 {
-                // Renormalize by incrementing the exponent and shifting our
-                // significand right one. However if we already have the
-                // maximum exponent we overflow to infinity.
-                if self.exp == S::MAX_EXP {
-                    self.category = Category::Infinity;
-
-                    return (Status::OVERFLOW | Status::INEXACT).and(self);
-                }
-
-                let _: Loss = sig::shift_right(&mut self.sig, &mut self.exp, 1);
-
-                return Status::INEXACT.and(self);
-            }
-        }
-
-        // The normal case - we were and are not denormal, and any
-        // significand increment above didn't overflow.
-        if omsb == S::PRECISION {
-            return Status::INEXACT.and(self);
-        }
-
-        // We have a non-zero denormal.
-        assert!(omsb < S::PRECISION);
-
-        // Canonicalize zeros.
-        if omsb == 0 {
-            self.category = Category::Zero;
-        }
-
-        // The Category::Zero case is a denormal that underflowed to zero.
-        (Status::UNDERFLOW | Status::INEXACT).and(self)
-    }
-
-    fn from_hexadecimal_string(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        let mut r = IeeeFloat {
-            sig: [0],
-            exp: 0,
-            category: Category::Normal,
-            sign: false,
-            marker: PhantomData,
-        };
-
-        let mut any_digits = false;
-        let mut has_exp = false;
-        let mut bit_pos = LIMB_BITS as isize;
-        let mut loss = None;
-
-        // Without leading or trailing zeros, irrespective of the dot.
-        let mut first_sig_digit = None;
-        let mut dot = s.len();
-
-        for (p, c) in s.char_indices() {
-            // Skip leading zeros and any (hexa)decimal point.
-            if c == '.' {
-                if dot != s.len() {
-                    return Err(ParseError("String contains multiple dots"));
-                }
-                dot = p;
-            } else if let Some(hex_value) = c.to_digit(16) {
-                any_digits = true;
-
-                if first_sig_digit.is_none() {
-                    if hex_value == 0 {
-                        continue;
-                    }
-                    first_sig_digit = Some(p);
-                }
-
-                // Store the number while we have space.
-                bit_pos -= 4;
-                if bit_pos >= 0 {
-                    r.sig[0] |= (hex_value as Limb) << bit_pos;
-                // If zero or one-half (the hexadecimal digit 8) are followed
-                // by non-zero, they're a little more than zero or one-half.
-                } else if let Some(ref mut loss) = loss {
-                    if hex_value != 0 {
-                        if *loss == Loss::ExactlyZero {
-                            *loss = Loss::LessThanHalf;
-                        }
-                        if *loss == Loss::ExactlyHalf {
-                            *loss = Loss::MoreThanHalf;
-                        }
-                    }
-                } else {
-                    loss = Some(match hex_value {
-                        0 => Loss::ExactlyZero,
-                        1..=7 => Loss::LessThanHalf,
-                        8 => Loss::ExactlyHalf,
-                        9..=15 => Loss::MoreThanHalf,
-                        _ => unreachable!(),
-                    });
-                }
-            } else if c == 'p' || c == 'P' {
-                if !any_digits {
-                    return Err(ParseError("Significand has no digits"));
-                }
-
-                if dot == s.len() {
-                    dot = p;
-                }
-
-                let mut chars = s[p + 1..].chars().peekable();
-
-                // Adjust for the given exponent.
-                let exp_minus = chars.peek() == Some(&'-');
-                if exp_minus || chars.peek() == Some(&'+') {
-                    chars.next();
-                }
-
-                for c in chars {
-                    if let Some(value) = c.to_digit(10) {
-                        has_exp = true;
-                        r.exp = r.exp.saturating_mul(10).saturating_add(value as ExpInt);
-                    } else {
-                        return Err(ParseError("Invalid character in exponent"));
-                    }
-                }
-                if !has_exp {
-                    return Err(ParseError("Exponent has no digits"));
-                }
-
-                if exp_minus {
-                    r.exp = -r.exp;
-                }
-
-                break;
-            } else {
-                return Err(ParseError("Invalid character in significand"));
-            }
-        }
-        if !any_digits {
-            return Err(ParseError("Significand has no digits"));
-        }
-
-        // Hex floats require an exponent but not a hexadecimal point.
-        if !has_exp {
-            return Err(ParseError("Hex strings require an exponent"));
-        }
-
-        // Ignore the exponent if we are zero.
-        let first_sig_digit = match first_sig_digit {
-            Some(p) => p,
-            None => return Ok(Status::OK.and(Self::ZERO)),
-        };
-
-        // Calculate the exponent adjustment implicit in the number of
-        // significant digits and adjust for writing the significand starting
-        // at the most significant nibble.
-        let exp_adjustment = if dot > first_sig_digit {
-            ExpInt::try_from(dot - first_sig_digit).unwrap()
-        } else {
-            -ExpInt::try_from(first_sig_digit - dot - 1).unwrap()
-        };
-        let exp_adjustment = exp_adjustment
-            .saturating_mul(4)
-            .saturating_sub(1)
-            .saturating_add(S::PRECISION as ExpInt)
-            .saturating_sub(LIMB_BITS as ExpInt);
-        r.exp = r.exp.saturating_add(exp_adjustment);
-
-        Ok(r.normalize(round, loss.unwrap_or(Loss::ExactlyZero)))
-    }
-
-    fn from_decimal_string(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        // Given a normal decimal floating point number of the form
-        //
-        //   dddd.dddd[eE][+-]ddd
-        //
-        // where the decimal point and exponent are optional, fill out the
-        // variables below. Exponent is appropriate if the significand is
-        // treated as an integer, and normalized_exp if the significand
-        // is taken to have the decimal point after a single leading
-        // non-zero digit.
-        //
-        // If the value is zero, first_sig_digit is None.
-
-        let mut any_digits = false;
-        let mut dec_exp = 0i32;
-
-        // Without leading or trailing zeros, irrespective of the dot.
-        let mut first_sig_digit = None;
-        let mut last_sig_digit = 0;
-        let mut dot = s.len();
-
-        for (p, c) in s.char_indices() {
-            if c == '.' {
-                if dot != s.len() {
-                    return Err(ParseError("String contains multiple dots"));
-                }
-                dot = p;
-            } else if let Some(dec_value) = c.to_digit(10) {
-                any_digits = true;
-
-                if dec_value != 0 {
-                    if first_sig_digit.is_none() {
-                        first_sig_digit = Some(p);
-                    }
-                    last_sig_digit = p;
-                }
-            } else if c == 'e' || c == 'E' {
-                if !any_digits {
-                    return Err(ParseError("Significand has no digits"));
-                }
-
-                if dot == s.len() {
-                    dot = p;
-                }
-
-                let mut chars = s[p + 1..].chars().peekable();
-
-                // Adjust for the given exponent.
-                let exp_minus = chars.peek() == Some(&'-');
-                if exp_minus || chars.peek() == Some(&'+') {
-                    chars.next();
-                }
-
-                any_digits = false;
-                for c in chars {
-                    if let Some(value) = c.to_digit(10) {
-                        any_digits = true;
-                        dec_exp = dec_exp.saturating_mul(10).saturating_add(value as i32);
-                    } else {
-                        return Err(ParseError("Invalid character in exponent"));
-                    }
-                }
-                if !any_digits {
-                    return Err(ParseError("Exponent has no digits"));
-                }
-
-                if exp_minus {
-                    dec_exp = -dec_exp;
-                }
-
-                break;
-            } else {
-                return Err(ParseError("Invalid character in significand"));
-            }
-        }
-        if !any_digits {
-            return Err(ParseError("Significand has no digits"));
-        }
-
-        // Test if we have a zero number allowing for non-zero exponents.
-        let first_sig_digit = match first_sig_digit {
-            Some(p) => p,
-            None => return Ok(Status::OK.and(Self::ZERO)),
-        };
-
-        // Adjust the exponents for any decimal point.
-        if dot > last_sig_digit {
-            dec_exp = dec_exp.saturating_add((dot - last_sig_digit - 1) as i32);
-        } else {
-            dec_exp = dec_exp.saturating_sub((last_sig_digit - dot) as i32);
-        }
-        let significand_digits = last_sig_digit - first_sig_digit + 1
-            - (dot > first_sig_digit && dot < last_sig_digit) as usize;
-        let normalized_exp = dec_exp.saturating_add(significand_digits as i32 - 1);
-
-        // Handle the cases where exponents are obviously too large or too
-        // small. Writing L for log 10 / log 2, a number d.ddddd*10^dec_exp
-        // definitely overflows if
-        //
-        //       (dec_exp - 1) * L >= MAX_EXP
-        //
-        // and definitely underflows to zero where
-        //
-        //       (dec_exp + 1) * L <= MIN_EXP - PRECISION
-        //
-        // With integer arithmetic the tightest bounds for L are
-        //
-        //       93/28 < L < 196/59            [ numerator <= 256 ]
-        //       42039/12655 < L < 28738/8651  [ numerator <= 65536 ]
-
-        // Check for MAX_EXP.
-        if normalized_exp.saturating_sub(1).saturating_mul(42039) >= 12655 * S::MAX_EXP as i32 {
-            // Overflow and round.
-            return Ok(Self::overflow_result(round));
-        }
-
-        // Check for MIN_EXP.
-        if normalized_exp.saturating_add(1).saturating_mul(28738)
-            <= 8651 * (S::MIN_EXP as i32 - S::PRECISION as i32)
-        {
-            // Underflow to zero and round.
-            let r =
-                if round == Round::TowardPositive { IeeeFloat::SMALLEST } else { IeeeFloat::ZERO };
-            return Ok((Status::UNDERFLOW | Status::INEXACT).and(r));
-        }
-
-        // A tight upper bound on number of bits required to hold an
-        // N-digit decimal integer is N * 196 / 59. Allocate enough space
-        // to hold the full significand, and an extra limb required by
-        // tcMultiplyPart.
-        let max_limbs = limbs_for_bits(1 + 196 * significand_digits / 59);
-        let mut dec_sig: SmallVec<[Limb; 1]> = SmallVec::with_capacity(max_limbs);
-
-        // Convert to binary efficiently - we do almost all multiplication
-        // in a Limb. When this would overflow do we do a single
-        // bignum multiplication, and then revert again to multiplication
-        // in a Limb.
-        let mut chars = s[first_sig_digit..=last_sig_digit].chars();
-        loop {
-            let mut val = 0;
-            let mut multiplier = 1;
-
-            loop {
-                let dec_value = match chars.next() {
-                    Some('.') => continue,
-                    Some(c) => c.to_digit(10).unwrap(),
-                    None => break,
-                };
-
-                multiplier *= 10;
-                val = val * 10 + dec_value as Limb;
-
-                // The maximum number that can be multiplied by ten with any
-                // digit added without overflowing a Limb.
-                if multiplier > (!0 - 9) / 10 {
-                    break;
-                }
-            }
-
-            // If we've consumed no digits, we're done.
-            if multiplier == 1 {
-                break;
-            }
-
-            // Multiply out the current limb.
-            let mut carry = val;
-            for x in &mut dec_sig {
-                let [low, mut high] = sig::widening_mul(*x, multiplier);
-
-                // Now add carry.
-                let (low, overflow) = low.overflowing_add(carry);
-                high += overflow as Limb;
-
-                *x = low;
-                carry = high;
-            }
-
-            // If we had carry, we need another limb (likely but not guaranteed).
-            if carry > 0 {
-                dec_sig.push(carry);
-            }
-        }
-
-        // Calculate pow(5, abs(dec_exp)) into `pow5_full`.
-        // The *_calc Vec's are reused scratch space, as an optimization.
-        let (pow5_full, mut pow5_calc, mut sig_calc, mut sig_scratch_calc) = {
-            let mut power = dec_exp.abs() as usize;
-
-            const FIRST_EIGHT_POWERS: [Limb; 8] = [1, 5, 25, 125, 625, 3125, 15625, 78125];
-
-            let mut p5_scratch = smallvec![];
-            let mut p5: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[4]];
-
-            let mut r_scratch = smallvec![];
-            let mut r: SmallVec<[Limb; 1]> = smallvec![FIRST_EIGHT_POWERS[power & 7]];
-            power >>= 3;
-
-            while power > 0 {
-                // Calculate pow(5,pow(2,n+3)).
-                p5_scratch.resize(p5.len() * 2, 0);
-                let _: Loss = sig::mul(&mut p5_scratch, &mut 0, &p5, &p5, p5.len() * 2 * LIMB_BITS);
-                while p5_scratch.last() == Some(&0) {
-                    p5_scratch.pop();
-                }
-                mem::swap(&mut p5, &mut p5_scratch);
-
-                if power & 1 != 0 {
-                    r_scratch.resize(r.len() + p5.len(), 0);
-                    let _: Loss =
-                        sig::mul(&mut r_scratch, &mut 0, &r, &p5, (r.len() + p5.len()) * LIMB_BITS);
-                    while r_scratch.last() == Some(&0) {
-                        r_scratch.pop();
-                    }
-                    mem::swap(&mut r, &mut r_scratch);
-                }
-
-                power >>= 1;
-            }
-
-            (r, r_scratch, p5, p5_scratch)
-        };
-
-        // Attempt dec_sig * 10^dec_exp with increasing precision.
-        let mut attempt = 0;
-        loop {
-            let calc_precision = (LIMB_BITS << attempt) - 1;
-            attempt += 1;
-
-            let calc_normal_from_limbs = |sig: &mut SmallVec<[Limb; 1]>,
-                                          limbs: &[Limb]|
-             -> StatusAnd<ExpInt> {
-                sig.resize(limbs_for_bits(calc_precision), 0);
-                let (mut loss, mut exp) = sig::from_limbs(sig, limbs, calc_precision);
-
-                // Before rounding normalize the exponent of Category::Normal numbers.
-                let mut omsb = sig::omsb(sig);
-
-                assert_ne!(omsb, 0);
-
-                // OMSB is numbered from 1. We want to place it in the integer
-                // bit numbered PRECISION if possible, with a compensating change in
-                // the exponent.
-                let final_exp = exp.saturating_add(omsb as ExpInt - calc_precision as ExpInt);
-
-                // Shifting left is easy as we don't lose precision.
-                if final_exp < exp {
-                    assert_eq!(loss, Loss::ExactlyZero);
-
-                    let exp_change = (exp - final_exp) as usize;
-                    sig::shift_left(sig, &mut exp, exp_change);
-
-                    return Status::OK.and(exp);
-                }
-
-                // Shift right and capture any new lost fraction.
-                if final_exp > exp {
-                    let exp_change = (final_exp - exp) as usize;
-                    loss = sig::shift_right(sig, &mut exp, exp_change).combine(loss);
-
-                    // Keep OMSB up-to-date.
-                    omsb = omsb.saturating_sub(exp_change);
-                }
-
-                assert_eq!(omsb, calc_precision);
-
-                // Now round the number according to round given the lost
-                // fraction.
-
-                // As specified in IEEE 754, since we do not trap we do not report
-                // underflow for exact results.
-                if loss == Loss::ExactlyZero {
-                    return Status::OK.and(exp);
-                }
-
-                // Increment the significand if we're rounding away from zero.
-                if loss == Loss::MoreThanHalf || loss == Loss::ExactlyHalf && sig::get_bit(sig, 0) {
-                    // We should never overflow.
-                    assert_eq!(sig::increment(sig), 0);
-                    omsb = sig::omsb(sig);
-
-                    // Did the significand increment overflow?
-                    if omsb == calc_precision + 1 {
-                        let _: Loss = sig::shift_right(sig, &mut exp, 1);
-
-                        return Status::INEXACT.and(exp);
-                    }
-                }
-
-                // The normal case - we were and are not denormal, and any
-                // significand increment above didn't overflow.
-                Status::INEXACT.and(exp)
-            };
-
-            let status;
-            let mut exp = unpack!(status=,
-                calc_normal_from_limbs(&mut sig_calc, &dec_sig));
-            let pow5_status;
-            let pow5_exp = unpack!(pow5_status=,
-                calc_normal_from_limbs(&mut pow5_calc, &pow5_full));
-
-            // Add dec_exp, as 10^n = 5^n * 2^n.
-            exp += dec_exp as ExpInt;
-
-            let mut used_bits = S::PRECISION;
-            let mut truncated_bits = calc_precision - used_bits;
-
-            let half_ulp_err1 = (status != Status::OK) as Limb;
-            let (calc_loss, half_ulp_err2);
-            if dec_exp >= 0 {
-                exp += pow5_exp;
-
-                sig_scratch_calc.resize(sig_calc.len() + pow5_calc.len(), 0);
-                calc_loss = sig::mul(
-                    &mut sig_scratch_calc,
-                    &mut exp,
-                    &sig_calc,
-                    &pow5_calc,
-                    calc_precision,
-                );
-                mem::swap(&mut sig_calc, &mut sig_scratch_calc);
-
-                half_ulp_err2 = (pow5_status != Status::OK) as Limb;
-            } else {
-                exp -= pow5_exp;
-
-                sig_scratch_calc.resize(sig_calc.len(), 0);
-                calc_loss = sig::div(
-                    &mut sig_scratch_calc,
-                    &mut exp,
-                    &mut sig_calc,
-                    &mut pow5_calc,
-                    calc_precision,
-                );
-                mem::swap(&mut sig_calc, &mut sig_scratch_calc);
-
-                // Denormal numbers have less precision.
-                if exp < S::MIN_EXP {
-                    truncated_bits += (S::MIN_EXP - exp) as usize;
-                    used_bits = calc_precision.saturating_sub(truncated_bits);
-                }
-                // Extra half-ulp lost in reciprocal of exponent.
-                half_ulp_err2 =
-                    2 * (pow5_status != Status::OK || calc_loss != Loss::ExactlyZero) as Limb;
-            }
-
-            // Both sig::mul and sig::div return the
-            // result with the integer bit set.
-            assert!(sig::get_bit(&sig_calc, calc_precision - 1));
-
-            // The error from the true value, in half-ulps, on multiplying two
-            // floating point numbers, which differ from the value they
-            // approximate by at most half_ulp_err1 and half_ulp_err2 half-ulps, is strictly less
-            // than the returned value.
-            //
-            // See "How to Read Floating Point Numbers Accurately" by William D Clinger.
-            assert!(half_ulp_err1 < 2 || half_ulp_err2 < 2 || (half_ulp_err1 + half_ulp_err2 < 8));
-
-            let inexact = (calc_loss != Loss::ExactlyZero) as Limb;
-            let half_ulp_err = if half_ulp_err1 + half_ulp_err2 == 0 {
-                inexact * 2 // <= inexact half-ulps.
-            } else {
-                inexact + 2 * (half_ulp_err1 + half_ulp_err2)
-            };
-
-            let ulps_from_boundary = {
-                let bits = calc_precision - used_bits - 1;
-
-                let i = bits / LIMB_BITS;
-                let limb = sig_calc[i] & (!0 >> (LIMB_BITS - 1 - bits % LIMB_BITS));
-                let boundary = match round {
-                    Round::NearestTiesToEven | Round::NearestTiesToAway => 1 << (bits % LIMB_BITS),
-                    _ => 0,
-                };
-                if i == 0 {
-                    let delta = limb.wrapping_sub(boundary);
-                    cmp::min(delta, delta.wrapping_neg())
-                } else if limb == boundary {
-                    if !sig::is_all_zeros(&sig_calc[1..i]) {
-                        !0 // A lot.
-                    } else {
-                        sig_calc[0]
-                    }
-                } else if limb == boundary.wrapping_sub(1) {
-                    if sig_calc[1..i].iter().any(|&x| x.wrapping_neg() != 1) {
-                        !0 // A lot.
-                    } else {
-                        sig_calc[0].wrapping_neg()
-                    }
-                } else {
-                    !0 // A lot.
-                }
-            };
-
-            // Are we guaranteed to round correctly if we truncate?
-            if ulps_from_boundary.saturating_mul(2) >= half_ulp_err {
-                let mut r = IeeeFloat {
-                    sig: [0],
-                    exp,
-                    category: Category::Normal,
-                    sign: false,
-                    marker: PhantomData,
-                };
-                sig::extract(&mut r.sig, &sig_calc, used_bits, calc_precision - used_bits);
-                // If we extracted less bits above we must adjust our exponent
-                // to compensate for the implicit right shift.
-                r.exp += (S::PRECISION - used_bits) as ExpInt;
-                let loss = Loss::through_truncation(&sig_calc, truncated_bits);
-                return Ok(r.normalize(round, loss));
-            }
-        }
-    }
-}
-
-impl Loss {
-    /// Combine the effect of two lost fractions.
-    fn combine(self, less_significant: Loss) -> Loss {
-        let mut more_significant = self;
-        if less_significant != Loss::ExactlyZero {
-            if more_significant == Loss::ExactlyZero {
-                more_significant = Loss::LessThanHalf;
-            } else if more_significant == Loss::ExactlyHalf {
-                more_significant = Loss::MoreThanHalf;
-            }
-        }
-
-        more_significant
-    }
-
-    /// Returns the fraction lost were a bignum truncated losing the least
-    /// significant `bits` bits.
-    fn through_truncation(limbs: &[Limb], bits: usize) -> Loss {
-        if bits == 0 {
-            return Loss::ExactlyZero;
-        }
-
-        let half_bit = bits - 1;
-        let half_limb = half_bit / LIMB_BITS;
-        let (half_limb, rest) = if half_limb < limbs.len() {
-            (limbs[half_limb], &limbs[..half_limb])
-        } else {
-            (0, limbs)
-        };
-        let half = 1 << (half_bit % LIMB_BITS);
-        let has_half = half_limb & half != 0;
-        let has_rest = half_limb & (half - 1) != 0 || !sig::is_all_zeros(rest);
-
-        match (has_half, has_rest) {
-            (false, false) => Loss::ExactlyZero,
-            (false, true) => Loss::LessThanHalf,
-            (true, false) => Loss::ExactlyHalf,
-            (true, true) => Loss::MoreThanHalf,
-        }
-    }
-}
-
-/// Implementation details of IeeeFloat significands, such as big integer arithmetic.
-/// As a rule of thumb, no functions in this module should dynamically allocate.
-mod sig {
-    use super::{limbs_for_bits, ExpInt, Limb, Loss, LIMB_BITS};
-    use core::cmp::Ordering;
-    use core::iter;
-    use core::mem;
-
-    pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool {
-        limbs.iter().all(|&l| l == 0)
-    }
-
-    /// One, not zero, based LSB. That is, returns 0 for a zeroed significand.
-    pub(super) fn olsb(limbs: &[Limb]) -> usize {
-        limbs
-            .iter()
-            .enumerate()
-            .find(|(_, &limb)| limb != 0)
-            .map_or(0, |(i, limb)| i * LIMB_BITS + limb.trailing_zeros() as usize + 1)
-    }
-
-    /// One, not zero, based MSB. That is, returns 0 for a zeroed significand.
-    pub(super) fn omsb(limbs: &[Limb]) -> usize {
-        limbs
-            .iter()
-            .enumerate()
-            .rfind(|(_, &limb)| limb != 0)
-            .map_or(0, |(i, limb)| (i + 1) * LIMB_BITS - limb.leading_zeros() as usize)
-    }
-
-    /// Comparison (unsigned) of two significands.
-    pub(super) fn cmp(a: &[Limb], b: &[Limb]) -> Ordering {
-        assert_eq!(a.len(), b.len());
-        for (a, b) in a.iter().zip(b).rev() {
-            match a.cmp(b) {
-                Ordering::Equal => {}
-                o => return o,
-            }
-        }
-
-        Ordering::Equal
-    }
-
-    /// Extracts the given bit.
-    pub(super) fn get_bit(limbs: &[Limb], bit: usize) -> bool {
-        limbs[bit / LIMB_BITS] & (1 << (bit % LIMB_BITS)) != 0
-    }
-
-    /// Sets the given bit.
-    pub(super) fn set_bit(limbs: &mut [Limb], bit: usize) {
-        limbs[bit / LIMB_BITS] |= 1 << (bit % LIMB_BITS);
-    }
-
-    /// Clear the given bit.
-    pub(super) fn clear_bit(limbs: &mut [Limb], bit: usize) {
-        limbs[bit / LIMB_BITS] &= !(1 << (bit % LIMB_BITS));
-    }
-
-    /// Shifts `dst` left `bits` bits, subtract `bits` from its exponent.
-    pub(super) fn shift_left(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) {
-        if bits > 0 {
-            // Our exponent should not underflow.
-            *exp = exp.checked_sub(bits as ExpInt).unwrap();
-
-            // Jump is the inter-limb jump; shift is the intra-limb shift.
-            let jump = bits / LIMB_BITS;
-            let shift = bits % LIMB_BITS;
-
-            for i in (0..dst.len()).rev() {
-                let mut limb;
-
-                if i < jump {
-                    limb = 0;
-                } else {
-                    // dst[i] comes from the two limbs src[i - jump] and, if we have
-                    // an intra-limb shift, src[i - jump - 1].
-                    limb = dst[i - jump];
-                    if shift > 0 {
-                        limb <<= shift;
-                        if i > jump {
-                            limb |= dst[i - jump - 1] >> (LIMB_BITS - shift);
-                        }
-                    }
-                }
-
-                dst[i] = limb;
-            }
-        }
-    }
-
-    /// Shifts `dst` right `bits` bits noting lost fraction.
-    pub(super) fn shift_right(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) -> Loss {
-        let loss = Loss::through_truncation(dst, bits);
-
-        if bits > 0 {
-            // Our exponent should not overflow.
-            *exp = exp.checked_add(bits as ExpInt).unwrap();
-
-            // Jump is the inter-limb jump; shift is the intra-limb shift.
-            let jump = bits / LIMB_BITS;
-            let shift = bits % LIMB_BITS;
-
-            // Perform the shift. This leaves the most significant `bits` bits
-            // of the result at zero.
-            for i in 0..dst.len() {
-                let mut limb;
-
-                if i + jump >= dst.len() {
-                    limb = 0;
-                } else {
-                    limb = dst[i + jump];
-                    if shift > 0 {
-                        limb >>= shift;
-                        if i + jump + 1 < dst.len() {
-                            limb |= dst[i + jump + 1] << (LIMB_BITS - shift);
-                        }
-                    }
-                }
-
-                dst[i] = limb;
-            }
-        }
-
-        loss
-    }
-
-    /// Copies the bit vector of width `src_bits` from `src`, starting at bit SRC_LSB,
-    /// to `dst`, such that the bit SRC_LSB becomes the least significant bit of `dst`.
-    /// All high bits above `src_bits` in `dst` are zero-filled.
-    pub(super) fn extract(dst: &mut [Limb], src: &[Limb], src_bits: usize, src_lsb: usize) {
-        if src_bits == 0 {
-            return;
-        }
-
-        let dst_limbs = limbs_for_bits(src_bits);
-        assert!(dst_limbs <= dst.len());
-
-        let src = &src[src_lsb / LIMB_BITS..];
-        dst[..dst_limbs].copy_from_slice(&src[..dst_limbs]);
-
-        let shift = src_lsb % LIMB_BITS;
-        let _: Loss = shift_right(&mut dst[..dst_limbs], &mut 0, shift);
-
-        // We now have (dst_limbs * LIMB_BITS - shift) bits from `src`
-        // in `dst`.  If this is less that src_bits, append the rest, else
-        // clear the high bits.
-        let n = dst_limbs * LIMB_BITS - shift;
-        if n < src_bits {
-            let mask = (1 << (src_bits - n)) - 1;
-            dst[dst_limbs - 1] |= (src[dst_limbs] & mask) << (n % LIMB_BITS);
-        } else if n > src_bits && src_bits % LIMB_BITS > 0 {
-            dst[dst_limbs - 1] &= (1 << (src_bits % LIMB_BITS)) - 1;
-        }
-
-        // Clear high limbs.
-        for x in &mut dst[dst_limbs..] {
-            *x = 0;
-        }
-    }
-
-    /// We want the most significant PRECISION bits of `src`. There may not
-    /// be that many; extract what we can.
-    pub(super) fn from_limbs(dst: &mut [Limb], src: &[Limb], precision: usize) -> (Loss, ExpInt) {
-        let omsb = omsb(src);
-
-        if precision <= omsb {
-            extract(dst, src, precision, omsb - precision);
-            (Loss::through_truncation(src, omsb - precision), omsb as ExpInt - 1)
-        } else {
-            extract(dst, src, omsb, 0);
-            (Loss::ExactlyZero, precision as ExpInt - 1)
-        }
-    }
-
-    /// For every consecutive chunk of `bits` bits from `limbs`,
-    /// going from most significant to the least significant bits,
-    /// call `f` to transform those bits and store the result back.
-    pub(super) fn each_chunk<F: FnMut(Limb) -> Limb>(limbs: &mut [Limb], bits: usize, mut f: F) {
-        assert_eq!(LIMB_BITS % bits, 0);
-        for limb in limbs.iter_mut().rev() {
-            let mut r = 0;
-            for i in (0..LIMB_BITS / bits).rev() {
-                r |= f((*limb >> (i * bits)) & ((1 << bits) - 1)) << (i * bits);
-            }
-            *limb = r;
-        }
-    }
-
-    /// Increment in-place, return the carry flag.
-    pub(super) fn increment(dst: &mut [Limb]) -> Limb {
-        for x in dst {
-            *x = x.wrapping_add(1);
-            if *x != 0 {
-                return 0;
-            }
-        }
-
-        1
-    }
-
-    /// Decrement in-place, return the borrow flag.
-    pub(super) fn decrement(dst: &mut [Limb]) -> Limb {
-        for x in dst {
-            *x = x.wrapping_sub(1);
-            if *x != !0 {
-                return 0;
-            }
-        }
-
-        1
-    }
-
-    /// `a += b + c` where `c` is zero or one. Returns the carry flag.
-    pub(super) fn add(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
-        assert!(c <= 1);
-
-        for (a, &b) in iter::zip(a, b) {
-            let (r, overflow) = a.overflowing_add(b);
-            let (r, overflow2) = r.overflowing_add(c);
-            *a = r;
-            c = (overflow | overflow2) as Limb;
-        }
-
-        c
-    }
-
-    /// `a -= b + c` where `c` is zero or one. Returns the borrow flag.
-    pub(super) fn sub(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb {
-        assert!(c <= 1);
-
-        for (a, &b) in iter::zip(a, b) {
-            let (r, overflow) = a.overflowing_sub(b);
-            let (r, overflow2) = r.overflowing_sub(c);
-            *a = r;
-            c = (overflow | overflow2) as Limb;
-        }
-
-        c
-    }
-
-    /// `a += b` or `a -= b`. Does not preserve `b`.
-    pub(super) fn add_or_sub(
-        a_sig: &mut [Limb],
-        a_exp: &mut ExpInt,
-        a_sign: &mut bool,
-        b_sig: &mut [Limb],
-        b_exp: ExpInt,
-        b_sign: bool,
-    ) -> Loss {
-        // Are we bigger exponent-wise than the RHS?
-        let bits = *a_exp - b_exp;
-
-        // Determine if the operation on the absolute values is effectively
-        // an addition or subtraction.
-        // Subtraction is more subtle than one might naively expect.
-        if *a_sign ^ b_sign {
-            let (reverse, loss);
-
-            if bits == 0 {
-                reverse = cmp(a_sig, b_sig) == Ordering::Less;
-                loss = Loss::ExactlyZero;
-            } else if bits > 0 {
-                loss = shift_right(b_sig, &mut 0, (bits - 1) as usize);
-                shift_left(a_sig, a_exp, 1);
-                reverse = false;
-            } else {
-                loss = shift_right(a_sig, a_exp, (-bits - 1) as usize);
-                shift_left(b_sig, &mut 0, 1);
-                reverse = true;
-            }
-
-            let borrow = (loss != Loss::ExactlyZero) as Limb;
-            if reverse {
-                // The code above is intended to ensure that no borrow is necessary.
-                assert_eq!(sub(b_sig, a_sig, borrow), 0);
-                a_sig.copy_from_slice(b_sig);
-                *a_sign = !*a_sign;
-            } else {
-                // The code above is intended to ensure that no borrow is necessary.
-                assert_eq!(sub(a_sig, b_sig, borrow), 0);
-            }
-
-            // Invert the lost fraction - it was on the RHS and subtracted.
-            match loss {
-                Loss::LessThanHalf => Loss::MoreThanHalf,
-                Loss::MoreThanHalf => Loss::LessThanHalf,
-                _ => loss,
-            }
-        } else {
-            let loss = if bits > 0 {
-                shift_right(b_sig, &mut 0, bits as usize)
-            } else {
-                shift_right(a_sig, a_exp, -bits as usize)
-            };
-            // We have a guard bit; generating a carry cannot happen.
-            assert_eq!(add(a_sig, b_sig, 0), 0);
-            loss
-        }
-    }
-
-    /// `[low, high] = a * b`.
-    ///
-    /// This cannot overflow, because
-    ///
-    /// `(n - 1) * (n - 1) + 2 * (n - 1) == (n - 1) * (n + 1)`
-    ///
-    /// which is less than n<sup>2</sup>.
-    pub(super) fn widening_mul(a: Limb, b: Limb) -> [Limb; 2] {
-        let mut wide = [0, 0];
-
-        if a == 0 || b == 0 {
-            return wide;
-        }
-
-        const HALF_BITS: usize = LIMB_BITS / 2;
-
-        let select = |limb, i| (limb >> (i * HALF_BITS)) & ((1 << HALF_BITS) - 1);
-        for i in 0..2 {
-            for j in 0..2 {
-                let mut x = [select(a, i) * select(b, j), 0];
-                shift_left(&mut x, &mut 0, (i + j) * HALF_BITS);
-                assert_eq!(add(&mut wide, &x, 0), 0);
-            }
-        }
-
-        wide
-    }
-
-    /// `dst = a * b` (for normal `a` and `b`). Returns the lost fraction.
-    pub(super) fn mul<'a>(
-        dst: &mut [Limb],
-        exp: &mut ExpInt,
-        mut a: &'a [Limb],
-        mut b: &'a [Limb],
-        precision: usize,
-    ) -> Loss {
-        // Put the narrower number on the `a` for less loops below.
-        if a.len() > b.len() {
-            mem::swap(&mut a, &mut b);
-        }
-
-        for x in &mut dst[..b.len()] {
-            *x = 0;
-        }
-
-        for i in 0..a.len() {
-            let mut carry = 0;
-            for j in 0..b.len() {
-                let [low, mut high] = widening_mul(a[i], b[j]);
-
-                // Now add carry.
-                let (low, overflow) = low.overflowing_add(carry);
-                high += overflow as Limb;
-
-                // And now `dst[i + j]`, and store the new low part there.
-                let (low, overflow) = low.overflowing_add(dst[i + j]);
-                high += overflow as Limb;
-
-                dst[i + j] = low;
-                carry = high;
-            }
-            dst[i + b.len()] = carry;
-        }
-
-        // Assume the operands involved in the multiplication are single-precision
-        // FP, and the two multiplicants are:
-        //     a = a23 . a22 ... a0 * 2^e1
-        //     b = b23 . b22 ... b0 * 2^e2
-        // the result of multiplication is:
-        //     dst = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
-        // Note that there are three significant bits at the left-hand side of the
-        // radix point: two for the multiplication, and an overflow bit for the
-        // addition (that will always be zero at this point). Move the radix point
-        // toward left by two bits, and adjust exponent accordingly.
-        *exp += 2;
-
-        // Convert the result having "2 * precision" significant-bits back to the one
-        // having "precision" significant-bits. First, move the radix point from
-        // poision "2*precision - 1" to "precision - 1". The exponent need to be
-        // adjusted by "2*precision - 1" - "precision - 1" = "precision".
-        *exp -= precision as ExpInt + 1;
-
-        // In case MSB resides at the left-hand side of radix point, shift the
-        // mantissa right by some amount to make sure the MSB reside right before
-        // the radix point (i.e., "MSB . rest-significant-bits").
-        //
-        // Note that the result is not normalized when "omsb < precision". So, the
-        // caller needs to call IeeeFloat::normalize() if normalized value is
-        // expected.
-        let omsb = omsb(dst);
-        if omsb <= precision { Loss::ExactlyZero } else { shift_right(dst, exp, omsb - precision) }
-    }
-
-    /// `quotient = dividend / divisor`. Returns the lost fraction.
-    /// Does not preserve `dividend` or `divisor`.
-    pub(super) fn div(
-        quotient: &mut [Limb],
-        exp: &mut ExpInt,
-        dividend: &mut [Limb],
-        divisor: &mut [Limb],
-        precision: usize,
-    ) -> Loss {
-        // Normalize the divisor.
-        let bits = precision - omsb(divisor);
-        shift_left(divisor, &mut 0, bits);
-        *exp += bits as ExpInt;
-
-        // Normalize the dividend.
-        let bits = precision - omsb(dividend);
-        shift_left(dividend, exp, bits);
-
-        // Division by 1.
-        let olsb_divisor = olsb(divisor);
-        if olsb_divisor == precision {
-            quotient.copy_from_slice(dividend);
-            return Loss::ExactlyZero;
-        }
-
-        // Ensure the dividend >= divisor initially for the loop below.
-        // Incidentally, this means that the division loop below is
-        // guaranteed to set the integer bit to one.
-        if cmp(dividend, divisor) == Ordering::Less {
-            shift_left(dividend, exp, 1);
-            assert_ne!(cmp(dividend, divisor), Ordering::Less)
-        }
-
-        // Helper for figuring out the lost fraction.
-        let lost_fraction = |dividend: &[Limb], divisor: &[Limb]| match cmp(dividend, divisor) {
-            Ordering::Greater => Loss::MoreThanHalf,
-            Ordering::Equal => Loss::ExactlyHalf,
-            Ordering::Less => {
-                if is_all_zeros(dividend) {
-                    Loss::ExactlyZero
-                } else {
-                    Loss::LessThanHalf
-                }
-            }
-        };
-
-        // Try to perform a (much faster) short division for small divisors.
-        let divisor_bits = precision - (olsb_divisor - 1);
-        macro_rules! try_short_div {
-            ($W:ty, $H:ty, $half:expr) => {
-                if divisor_bits * 2 <= $half {
-                    // Extract the small divisor.
-                    let _: Loss = shift_right(divisor, &mut 0, olsb_divisor - 1);
-                    let divisor = divisor[0] as $H as $W;
-
-                    // Shift the dividend to produce a quotient with the unit bit set.
-                    let top_limb = *dividend.last().unwrap();
-                    let mut rem = (top_limb >> (LIMB_BITS - (divisor_bits - 1))) as $H;
-                    shift_left(dividend, &mut 0, divisor_bits - 1);
-
-                    // Apply short division in place on $H (of $half bits) chunks.
-                    each_chunk(dividend, $half, |chunk| {
-                        let chunk = chunk as $H;
-                        let combined = ((rem as $W) << $half) | (chunk as $W);
-                        rem = (combined % divisor) as $H;
-                        (combined / divisor) as $H as Limb
-                    });
-                    quotient.copy_from_slice(dividend);
-
-                    return lost_fraction(&[(rem as Limb) << 1], &[divisor as Limb]);
-                }
-            };
-        }
-
-        try_short_div!(u32, u16, 16);
-        try_short_div!(u64, u32, 32);
-        try_short_div!(u128, u64, 64);
-
-        // Zero the quotient before setting bits in it.
-        for x in &mut quotient[..limbs_for_bits(precision)] {
-            *x = 0;
-        }
-
-        // Long division.
-        for bit in (0..precision).rev() {
-            if cmp(dividend, divisor) != Ordering::Less {
-                sub(dividend, divisor, 0);
-                set_bit(quotient, bit);
-            }
-            shift_left(dividend, &mut 0, 1);
-        }
-
-        lost_fraction(dividend, divisor)
-    }
-}
diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs
deleted file mode 100644
index dde368e..0000000
--- a/compiler/rustc_apfloat/src/lib.rs
+++ /dev/null
@@ -1,695 +0,0 @@
-//! Port of LLVM's APFloat software floating-point implementation from the
-//! following C++ sources (please update commit hash when backporting):
-//! <https://github.com/llvm-mirror/llvm/tree/23efab2bbd424ed13495a420ad8641cb2c6c28f9>
-//!
-//! * `include/llvm/ADT/APFloat.h` -> `Float` and `FloatConvert` traits
-//! * `lib/Support/APFloat.cpp` -> `ieee` and `ppc` modules
-//! * `unittests/ADT/APFloatTest.cpp` -> `tests` directory
-//!
-//! The port contains no unsafe code, global state, or side-effects in general,
-//! and the only allocations are in the conversion to/from decimal strings.
-//!
-//! Most of the API and the testcases are intact in some form or another,
-//! with some ergonomic changes, such as idiomatic short names, returning
-//! new values instead of mutating the receiver, and having separate method
-//! variants that take a non-default rounding mode (with the suffix `_r`).
-//! Comments have been preserved where possible, only slightly adapted.
-//!
-//! Instead of keeping a pointer to a configuration struct and inspecting it
-//! dynamically on every operation, types (e.g., `ieee::Double`), traits
-//! (e.g., `ieee::Semantics`) and associated constants are employed for
-//! increased type safety and performance.
-//!
-//! On-heap bigints are replaced everywhere (except in decimal conversion),
-//! with short arrays of `type Limb = u128` elements (instead of `u64`),
-//! This allows fitting the largest supported significands in one integer
-//! (`ieee::Quad` and `ppc::Fallback` use slightly less than 128 bits).
-//! All of the functions in the `ieee::sig` module operate on slices.
-//!
-//! # Note
-//!
-//! This API is completely unstable and subject to change.
-
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![no_std]
-#![forbid(unsafe_code)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-
-#[macro_use]
-extern crate alloc;
-
-use core::cmp::Ordering;
-use core::fmt;
-use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
-use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
-use core::str::FromStr;
-
-bitflags::bitflags! {
-    /// IEEE-754R 7: Default exception handling.
-    ///
-    /// UNDERFLOW or OVERFLOW are always returned or-ed with INEXACT.
-    #[must_use]
-    pub struct Status: u8 {
-        const OK = 0x00;
-        const INVALID_OP = 0x01;
-        const DIV_BY_ZERO = 0x02;
-        const OVERFLOW = 0x04;
-        const UNDERFLOW = 0x08;
-        const INEXACT = 0x10;
-    }
-}
-
-#[must_use]
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub struct StatusAnd<T> {
-    pub status: Status,
-    pub value: T,
-}
-
-impl Status {
-    pub fn and<T>(self, value: T) -> StatusAnd<T> {
-        StatusAnd { status: self, value }
-    }
-}
-
-impl<T> StatusAnd<T> {
-    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> StatusAnd<U> {
-        StatusAnd { status: self.status, value: f(self.value) }
-    }
-}
-
-#[macro_export]
-macro_rules! unpack {
-    ($status:ident|=, $e:expr) => {
-        match $e {
-            $crate::StatusAnd { status, value } => {
-                $status |= status;
-                value
-            }
-        }
-    };
-    ($status:ident=, $e:expr) => {
-        match $e {
-            $crate::StatusAnd { status, value } => {
-                $status = status;
-                value
-            }
-        }
-    };
-}
-
-/// Category of internally-represented number.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Category {
-    Infinity,
-    NaN,
-    Normal,
-    Zero,
-}
-
-/// IEEE-754R 4.3: Rounding-direction attributes.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Round {
-    NearestTiesToEven,
-    TowardPositive,
-    TowardNegative,
-    TowardZero,
-    NearestTiesToAway,
-}
-
-impl Neg for Round {
-    type Output = Round;
-    fn neg(self) -> Round {
-        match self {
-            Round::TowardPositive => Round::TowardNegative,
-            Round::TowardNegative => Round::TowardPositive,
-            Round::NearestTiesToEven | Round::TowardZero | Round::NearestTiesToAway => self,
-        }
-    }
-}
-
-/// A signed type to represent a floating point number's unbiased exponent.
-pub type ExpInt = i16;
-
-// \c ilogb error results.
-pub const IEK_INF: ExpInt = ExpInt::MAX;
-pub const IEK_NAN: ExpInt = ExpInt::MIN;
-pub const IEK_ZERO: ExpInt = ExpInt::MIN + 1;
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct ParseError(pub &'static str);
-
-/// A self-contained host- and target-independent arbitrary-precision
-/// floating-point software implementation.
-///
-/// `apfloat` uses significand bignum integer arithmetic as provided by functions
-/// in the `ieee::sig`.
-///
-/// Written for clarity rather than speed, in particular with a view to use in
-/// the front-end of a cross compiler so that target arithmetic can be correctly
-/// performed on the host. Performance should nonetheless be reasonable,
-/// particularly for its intended use. It may be useful as a base
-/// implementation for a run-time library during development of a faster
-/// target-specific one.
-///
-/// All 5 rounding modes in the IEEE-754R draft are handled correctly for all
-/// implemented operations. Currently implemented operations are add, subtract,
-/// multiply, divide, fused-multiply-add, conversion-to-float,
-/// conversion-to-integer and conversion-from-integer. New rounding modes
-/// (e.g., away from zero) can be added with three or four lines of code.
-///
-/// Four formats are built-in: IEEE single precision, double precision,
-/// quadruple precision, and x87 80-bit extended double (when operating with
-/// full extended precision). Adding a new format that obeys IEEE semantics
-/// only requires adding two lines of code: a declaration and definition of the
-/// format.
-///
-/// All operations return the status of that operation as an exception bit-mask,
-/// so multiple operations can be done consecutively with their results or-ed
-/// together. The returned status can be useful for compiler diagnostics; e.g.,
-/// inexact, underflow and overflow can be easily diagnosed on constant folding,
-/// and compiler optimizers can determine what exceptions would be raised by
-/// folding operations and optimize, or perhaps not optimize, accordingly.
-///
-/// At present, underflow tininess is detected after rounding; it should be
-/// straight forward to add support for the before-rounding case too.
-///
-/// The library reads hexadecimal floating point numbers as per C99, and
-/// correctly rounds if necessary according to the specified rounding mode.
-/// Syntax is required to have been validated by the caller.
-///
-/// It also reads decimal floating point numbers and correctly rounds according
-/// to the specified rounding mode.
-///
-/// Non-zero finite numbers are represented internally as a sign bit, a 16-bit
-/// signed exponent, and the significand as an array of integer limbs. After
-/// normalization of a number of precision P the exponent is within the range of
-/// the format, and if the number is not denormal the P-th bit of the
-/// significand is set as an explicit integer bit. For denormals the most
-/// significant bit is shifted right so that the exponent is maintained at the
-/// format's minimum, so that the smallest denormal has just the least
-/// significant bit of the significand set. The sign of zeros and infinities
-/// is significant; the exponent and significand of such numbers is not stored,
-/// but has a known implicit (deterministic) value: 0 for the significands, 0
-/// for zero exponent, all 1 bits for infinity exponent. For NaNs the sign and
-/// significand are deterministic, although not really meaningful, and preserved
-/// in non-conversion operations. The exponent is implicitly all 1 bits.
-///
-/// `apfloat` does not provide any exception handling beyond default exception
-/// handling. We represent Signaling NaNs via IEEE-754R 2008 6.2.1 should clause
-/// by encoding Signaling NaNs with the first bit of its trailing significand
-/// as 0.
-///
-/// Future work
-/// ===========
-///
-/// Some features that may or may not be worth adding:
-///
-/// Optional ability to detect underflow tininess before rounding.
-///
-/// New formats: x87 in single and double precision mode (IEEE apart from
-/// extended exponent range) (hard).
-///
-/// New operations: sqrt, nexttoward.
-///
-pub trait Float:
-    Copy
-    + Default
-    + FromStr<Err = ParseError>
-    + PartialOrd
-    + fmt::Display
-    + Neg<Output = Self>
-    + AddAssign
-    + SubAssign
-    + MulAssign
-    + DivAssign
-    + RemAssign
-    + Add<Output = StatusAnd<Self>>
-    + Sub<Output = StatusAnd<Self>>
-    + Mul<Output = StatusAnd<Self>>
-    + Div<Output = StatusAnd<Self>>
-    + Rem<Output = StatusAnd<Self>>
-{
-    /// Total number of bits in the in-memory format.
-    const BITS: usize;
-
-    /// Number of bits in the significand. This includes the integer bit.
-    const PRECISION: usize;
-
-    /// The largest E such that 2<sup>E</sup> is representable; this matches the
-    /// definition of IEEE 754.
-    const MAX_EXP: ExpInt;
-
-    /// The smallest E such that 2<sup>E</sup> is a normalized number; this
-    /// matches the definition of IEEE 754.
-    const MIN_EXP: ExpInt;
-
-    /// Positive Zero.
-    const ZERO: Self;
-
-    /// Positive Infinity.
-    const INFINITY: Self;
-
-    /// NaN (Not a Number).
-    // FIXME(eddyb) provide a default when qnan becomes const fn.
-    const NAN: Self;
-
-    /// Factory for QNaN values.
-    // FIXME(eddyb) should be const fn.
-    fn qnan(payload: Option<u128>) -> Self;
-
-    /// Factory for SNaN values.
-    // FIXME(eddyb) should be const fn.
-    fn snan(payload: Option<u128>) -> Self;
-
-    /// Largest finite number.
-    // FIXME(eddyb) should be const (but FloatPair::largest is nontrivial).
-    fn largest() -> Self;
-
-    /// Smallest (by magnitude) finite number.
-    /// Might be denormalized, which implies a relative loss of precision.
-    const SMALLEST: Self;
-
-    /// Smallest (by magnitude) normalized finite number.
-    // FIXME(eddyb) should be const (but FloatPair::smallest_normalized is nontrivial).
-    fn smallest_normalized() -> Self;
-
-    // Arithmetic
-
-    fn add_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    fn sub_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        self.add_r(-rhs, round)
-    }
-    fn mul_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self>;
-    fn mul_add(self, multiplicand: Self, addend: Self) -> StatusAnd<Self> {
-        self.mul_add_r(multiplicand, addend, Round::NearestTiesToEven)
-    }
-    fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self>;
-    /// IEEE remainder.
-    // This is not currently correct in all cases.
-    fn ieee_rem(self, rhs: Self) -> StatusAnd<Self> {
-        let mut v = self;
-
-        let status;
-        v = unpack!(status=, v / rhs);
-        if status == Status::DIV_BY_ZERO {
-            return status.and(self);
-        }
-
-        assert!(Self::PRECISION < 128);
-
-        let status;
-        let x = unpack!(status=, v.to_i128_r(128, Round::NearestTiesToEven, &mut false));
-        if status == Status::INVALID_OP {
-            return status.and(self);
-        }
-
-        let status;
-        let mut v = unpack!(status=, Self::from_i128(x));
-        assert_eq!(status, Status::OK); // should always work
-
-        let status;
-        v = unpack!(status=, v * rhs);
-        assert_eq!(status - Status::INEXACT, Status::OK); // should not overflow or underflow
-
-        let status;
-        v = unpack!(status=, self - v);
-        assert_eq!(status - Status::INEXACT, Status::OK); // likewise
-
-        if v.is_zero() {
-            status.and(v.copy_sign(self)) // IEEE754 requires this
-        } else {
-            status.and(v)
-        }
-    }
-    /// C fmod, or llvm frem.
-    fn c_fmod(self, rhs: Self) -> StatusAnd<Self>;
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self>;
-
-    /// IEEE-754R 2008 5.3.1: nextUp.
-    fn next_up(self) -> StatusAnd<Self>;
-
-    /// IEEE-754R 2008 5.3.1: nextDown.
-    ///
-    /// *NOTE* since nextDown(x) = -nextUp(-x), we only implement nextUp with
-    /// appropriate sign switching before/after the computation.
-    fn next_down(self) -> StatusAnd<Self> {
-        (-self).next_up().map(|r| -r)
-    }
-
-    fn abs(self) -> Self {
-        if self.is_negative() { -self } else { self }
-    }
-    fn copy_sign(self, rhs: Self) -> Self {
-        if self.is_negative() != rhs.is_negative() { -self } else { self }
-    }
-
-    // Conversions
-    fn from_bits(input: u128) -> Self;
-    fn from_i128_r(input: i128, round: Round) -> StatusAnd<Self> {
-        if input < 0 {
-            Self::from_u128_r(input.wrapping_neg() as u128, -round).map(|r| -r)
-        } else {
-            Self::from_u128_r(input as u128, round)
-        }
-    }
-    fn from_i128(input: i128) -> StatusAnd<Self> {
-        Self::from_i128_r(input, Round::NearestTiesToEven)
-    }
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self>;
-    fn from_u128(input: u128) -> StatusAnd<Self> {
-        Self::from_u128_r(input, Round::NearestTiesToEven)
-    }
-    fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError>;
-    fn to_bits(self) -> u128;
-
-    /// Converts a floating point number to an integer according to the
-    /// rounding mode. In case of an invalid operation exception,
-    /// deterministic values are returned, namely zero for NaNs and the
-    /// minimal or maximal value respectively for underflow or overflow.
-    /// If the rounded value is in range but the floating point number is
-    /// not the exact integer, the C standard doesn't require an inexact
-    /// exception to be raised. IEEE-854 does require it so we do that.
-    ///
-    /// Note that for conversions to integer type the C standard requires
-    /// round-to-zero to always be used.
-    ///
-    /// The *is_exact output tells whether the result is exact, in the sense
-    /// that converting it back to the original floating point type produces
-    /// the original value. This is almost equivalent to `result == Status::OK`,
-    /// except for negative zeroes.
-    fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<i128> {
-        let status;
-        if self.is_negative() {
-            if self.is_zero() {
-                // Negative zero can't be represented as an int.
-                *is_exact = false;
-            }
-            let r = unpack!(status=, (-self).to_u128_r(width, -round, is_exact));
-
-            // Check for values that don't fit in the signed integer.
-            if r > (1 << (width - 1)) {
-                // Return the most negative integer for the given width.
-                *is_exact = false;
-                Status::INVALID_OP.and(-1 << (width - 1))
-            } else {
-                status.and(r.wrapping_neg() as i128)
-            }
-        } else {
-            // Positive case is simpler, can pretend it's a smaller unsigned
-            // integer, and `to_u128` will take care of all the edge cases.
-            self.to_u128_r(width - 1, round, is_exact).map(|r| r as i128)
-        }
-    }
-    fn to_i128(self, width: usize) -> StatusAnd<i128> {
-        self.to_i128_r(width, Round::TowardZero, &mut true)
-    }
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128>;
-    fn to_u128(self, width: usize) -> StatusAnd<u128> {
-        self.to_u128_r(width, Round::TowardZero, &mut true)
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering;
-
-    /// Bitwise comparison for equality (QNaNs compare equal, 0!=-0).
-    fn bitwise_eq(self, rhs: Self) -> bool;
-
-    // IEEE-754R 5.7.2 General operations.
-
-    /// Implements IEEE minNum semantics. Returns the smaller of the 2 arguments if
-    /// both are not NaN. If either argument is a NaN, returns the other argument.
-    fn min(self, other: Self) -> Self {
-        if self.is_nan() {
-            other
-        } else if other.is_nan() {
-            self
-        } else if other.partial_cmp(&self) == Some(Ordering::Less) {
-            other
-        } else {
-            self
-        }
-    }
-
-    /// Implements IEEE maxNum semantics. Returns the larger of the 2 arguments if
-    /// both are not NaN. If either argument is a NaN, returns the other argument.
-    fn max(self, other: Self) -> Self {
-        if self.is_nan() {
-            other
-        } else if other.is_nan() {
-            self
-        } else if self.partial_cmp(&other) == Some(Ordering::Less) {
-            other
-        } else {
-            self
-        }
-    }
-
-    /// IEEE-754R isSignMinus: Returns whether the current value is
-    /// negative.
-    ///
-    /// This applies to zeros and NaNs as well.
-    fn is_negative(self) -> bool;
-
-    /// IEEE-754R isNormal: Returns whether the current value is normal.
-    ///
-    /// This implies that the current value of the float is not zero, subnormal,
-    /// infinite, or NaN following the definition of normality from IEEE-754R.
-    fn is_normal(self) -> bool {
-        !self.is_denormal() && self.is_finite_non_zero()
-    }
-
-    /// Returns `true` if the current value is zero, subnormal, or
-    /// normal.
-    ///
-    /// This means that the value is not infinite or NaN.
-    fn is_finite(self) -> bool {
-        !self.is_nan() && !self.is_infinite()
-    }
-
-    /// Returns `true` if the float is plus or minus zero.
-    fn is_zero(self) -> bool {
-        self.category() == Category::Zero
-    }
-
-    /// IEEE-754R isSubnormal(): Returns whether the float is a
-    /// denormal.
-    fn is_denormal(self) -> bool;
-
-    /// IEEE-754R isInfinite(): Returns whether the float is infinity.
-    fn is_infinite(self) -> bool {
-        self.category() == Category::Infinity
-    }
-
-    /// Returns `true` if the float is a quiet or signaling NaN.
-    fn is_nan(self) -> bool {
-        self.category() == Category::NaN
-    }
-
-    /// Returns `true` if the float is a signaling NaN.
-    fn is_signaling(self) -> bool;
-
-    // Simple Queries
-
-    fn category(self) -> Category;
-    fn is_non_zero(self) -> bool {
-        !self.is_zero()
-    }
-    fn is_finite_non_zero(self) -> bool {
-        self.is_finite() && !self.is_zero()
-    }
-    fn is_pos_zero(self) -> bool {
-        self.is_zero() && !self.is_negative()
-    }
-    fn is_neg_zero(self) -> bool {
-        self.is_zero() && self.is_negative()
-    }
-
-    /// Returns `true` if the number has the smallest possible non-zero
-    /// magnitude in the current semantics.
-    fn is_smallest(self) -> bool {
-        Self::SMALLEST.copy_sign(self).bitwise_eq(self)
-    }
-
-    /// Returns `true` if the number has the largest possible finite
-    /// magnitude in the current semantics.
-    fn is_largest(self) -> bool {
-        Self::largest().copy_sign(self).bitwise_eq(self)
-    }
-
-    /// Returns `true` if the number is an exact integer.
-    fn is_integer(self) -> bool {
-        // This could be made more efficient; I'm going for obviously correct.
-        if !self.is_finite() {
-            return false;
-        }
-        self.round_to_integral(Round::TowardZero).value.bitwise_eq(self)
-    }
-
-    /// If this value has an exact multiplicative inverse, return it.
-    fn get_exact_inverse(self) -> Option<Self>;
-
-    /// Returns the exponent of the internal representation of the Float.
-    ///
-    /// Because the radix of Float is 2, this is equivalent to floor(log2(x)).
-    /// For special Float values, this returns special error codes:
-    ///
-    ///   NaN -> \c IEK_NAN
-    ///   0   -> \c IEK_ZERO
-    ///   Inf -> \c IEK_INF
-    ///
-    fn ilogb(self) -> ExpInt;
-
-    /// Returns: self * 2<sup>exp</sup> for integral exponents.
-    /// Equivalent to C standard library function `ldexp`.
-    fn scalbn_r(self, exp: ExpInt, round: Round) -> Self;
-    fn scalbn(self, exp: ExpInt) -> Self {
-        self.scalbn_r(exp, Round::NearestTiesToEven)
-    }
-
-    /// Equivalent to C standard library function with the same name.
-    ///
-    /// While the C standard says exp is an unspecified value for infinity and nan,
-    /// this returns INT_MAX for infinities, and INT_MIN for NaNs (see `ilogb`).
-    fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self;
-    fn frexp(self, exp: &mut ExpInt) -> Self {
-        self.frexp_r(exp, Round::NearestTiesToEven)
-    }
-}
-
-pub trait FloatConvert<T: Float>: Float {
-    /// Converts a value of one floating point type to another.
-    /// The return value corresponds to the IEEE754 exceptions. *loses_info
-    /// records whether the transformation lost information, i.e., whether
-    /// converting the result back to the original type will produce the
-    /// original value (this is almost the same as return `value == Status::OK`,
-    /// but there are edge cases where this is not so).
-    fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd<T>;
-    fn convert(self, loses_info: &mut bool) -> StatusAnd<T> {
-        self.convert_r(Round::NearestTiesToEven, loses_info)
-    }
-}
-
-macro_rules! float_common_impls {
-    ($ty:ident<$t:tt>) => {
-        impl<$t> Default for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn default() -> Self {
-                Self::ZERO
-            }
-        }
-
-        impl<$t> ::core::str::FromStr for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Err = ParseError;
-            fn from_str(s: &str) -> Result<Self, ParseError> {
-                Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value)
-            }
-        }
-
-        // Rounding ties to the nearest even, by default.
-
-        impl<$t> ::core::ops::Add for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn add(self, rhs: Self) -> StatusAnd<Self> {
-                self.add_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Sub for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn sub(self, rhs: Self) -> StatusAnd<Self> {
-                self.sub_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Mul for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn mul(self, rhs: Self) -> StatusAnd<Self> {
-                self.mul_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Div for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn div(self, rhs: Self) -> StatusAnd<Self> {
-                self.div_r(rhs, Round::NearestTiesToEven)
-            }
-        }
-
-        impl<$t> ::core::ops::Rem for $ty<$t>
-        where
-            Self: Float,
-        {
-            type Output = StatusAnd<Self>;
-            fn rem(self, rhs: Self) -> StatusAnd<Self> {
-                self.c_fmod(rhs)
-            }
-        }
-
-        impl<$t> ::core::ops::AddAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn add_assign(&mut self, rhs: Self) {
-                *self = (*self + rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::SubAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn sub_assign(&mut self, rhs: Self) {
-                *self = (*self - rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::MulAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn mul_assign(&mut self, rhs: Self) {
-                *self = (*self * rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::DivAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn div_assign(&mut self, rhs: Self) {
-                *self = (*self / rhs).value;
-            }
-        }
-
-        impl<$t> ::core::ops::RemAssign for $ty<$t>
-        where
-            Self: Float,
-        {
-            fn rem_assign(&mut self, rhs: Self) {
-                *self = (*self % rhs).value;
-            }
-        }
-    };
-}
-
-pub mod ieee;
-pub mod ppc;
diff --git a/compiler/rustc_apfloat/src/ppc.rs b/compiler/rustc_apfloat/src/ppc.rs
deleted file mode 100644
index 65a0f66..0000000
--- a/compiler/rustc_apfloat/src/ppc.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-use crate::ieee;
-use crate::{Category, ExpInt, Float, FloatConvert, ParseError, Round, Status, StatusAnd};
-
-use core::cmp::Ordering;
-use core::fmt;
-use core::ops::Neg;
-
-#[must_use]
-#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
-pub struct DoubleFloat<F>(F, F);
-pub type DoubleDouble = DoubleFloat<ieee::Double>;
-
-// These are legacy semantics for the Fallback, inaccurate implementation of
-// IBM double-double, if the accurate DoubleDouble doesn't handle the
-// operation. It's equivalent to having an IEEE number with consecutive 106
-// bits of mantissa and 11 bits of exponent.
-//
-// It's not equivalent to IBM double-double. For example, a legit IBM
-// double-double, 1 + epsilon:
-//
-//   1 + epsilon = 1 + (1 >> 1076)
-//
-// is not representable by a consecutive 106 bits of mantissa.
-//
-// Currently, these semantics are used in the following way:
-//
-//   DoubleDouble -> (Double, Double) ->
-//   DoubleDouble's Fallback -> IEEE operations
-//
-// FIXME: Implement all operations in DoubleDouble, and delete these
-// semantics.
-// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackS<F>(#[allow(unused)] F);
-type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
-impl<F: Float> ieee::Semantics for FallbackS<F> {
-    // Forbid any conversion to/from bits.
-    const BITS: usize = 0;
-    const PRECISION: usize = F::PRECISION * 2;
-    const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
-    const MIN_EXP: ExpInt = F::MIN_EXP as ExpInt + F::PRECISION as ExpInt;
-}
-
-// Convert number to F. To avoid spurious underflows, we re-
-// normalize against the F exponent range first, and only *then*
-// truncate the mantissa. The result of that second conversion
-// may be inexact, but should never underflow.
-// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackExtendedS<F>(#[allow(unused)] F);
-type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
-impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
-    // Forbid any conversion to/from bits.
-    const BITS: usize = 0;
-    const PRECISION: usize = Fallback::<F>::PRECISION;
-    const MAX_EXP: ExpInt = F::MAX_EXP as ExpInt;
-}
-
-impl<F: Float> From<Fallback<F>> for DoubleFloat<F>
-where
-    F: FloatConvert<FallbackExtended<F>>,
-    FallbackExtended<F>: FloatConvert<F>,
-{
-    fn from(x: Fallback<F>) -> Self {
-        let mut status;
-        let mut loses_info = false;
-
-        let extended: FallbackExtended<F> = unpack!(status=, x.convert(&mut loses_info));
-        assert_eq!((status, loses_info), (Status::OK, false));
-
-        let a = unpack!(status=, extended.convert(&mut loses_info));
-        assert_eq!(status - Status::INEXACT, Status::OK);
-
-        // If conversion was exact or resulted in a special case, we're done;
-        // just set the second double to zero. Otherwise, re-convert back to
-        // the extended format and compute the difference. This now should
-        // convert exactly to double.
-        let b = if a.is_finite_non_zero() && loses_info {
-            let u: FallbackExtended<F> = unpack!(status=, a.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-            let v = unpack!(status=, extended - u);
-            assert_eq!(status, Status::OK);
-            let v = unpack!(status=, v.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-            v
-        } else {
-            F::ZERO
-        };
-
-        DoubleFloat(a, b)
-    }
-}
-
-impl<F: FloatConvert<Self>> From<DoubleFloat<F>> for Fallback<F> {
-    fn from(DoubleFloat(a, b): DoubleFloat<F>) -> Self {
-        let mut status;
-        let mut loses_info = false;
-
-        // Get the first F and convert to our format.
-        let a = unpack!(status=, a.convert(&mut loses_info));
-        assert_eq!((status, loses_info), (Status::OK, false));
-
-        // Unless we have a special case, add in second F.
-        if a.is_finite_non_zero() {
-            let b = unpack!(status=, b.convert(&mut loses_info));
-            assert_eq!((status, loses_info), (Status::OK, false));
-
-            (a + b).value
-        } else {
-            a
-        }
-    }
-}
-
-float_common_impls!(DoubleFloat<F>);
-
-impl<F: Float> Neg for DoubleFloat<F> {
-    type Output = Self;
-    fn neg(self) -> Self {
-        if self.1.is_finite_non_zero() {
-            DoubleFloat(-self.0, -self.1)
-        } else {
-            DoubleFloat(-self.0, self.1)
-        }
-    }
-}
-
-impl<F: FloatConvert<Fallback<F>>> fmt::Display for DoubleFloat<F> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(&Fallback::from(*self), f)
-    }
-}
-
-impl<F: FloatConvert<Fallback<F>>> Float for DoubleFloat<F>
-where
-    Self: From<Fallback<F>>,
-{
-    const BITS: usize = F::BITS * 2;
-    const PRECISION: usize = Fallback::<F>::PRECISION;
-    const MAX_EXP: ExpInt = Fallback::<F>::MAX_EXP;
-    const MIN_EXP: ExpInt = Fallback::<F>::MIN_EXP;
-
-    const ZERO: Self = DoubleFloat(F::ZERO, F::ZERO);
-
-    const INFINITY: Self = DoubleFloat(F::INFINITY, F::ZERO);
-
-    // FIXME(eddyb) remove when qnan becomes const fn.
-    const NAN: Self = DoubleFloat(F::NAN, F::ZERO);
-
-    fn qnan(payload: Option<u128>) -> Self {
-        DoubleFloat(F::qnan(payload), F::ZERO)
-    }
-
-    fn snan(payload: Option<u128>) -> Self {
-        DoubleFloat(F::snan(payload), F::ZERO)
-    }
-
-    fn largest() -> Self {
-        let status;
-        let mut r = DoubleFloat(F::largest(), F::largest());
-        r.1 = r.1.scalbn(-(F::PRECISION as ExpInt + 1));
-        r.1 = unpack!(status=, r.1.next_down());
-        assert_eq!(status, Status::OK);
-        r
-    }
-
-    const SMALLEST: Self = DoubleFloat(F::SMALLEST, F::ZERO);
-
-    fn smallest_normalized() -> Self {
-        DoubleFloat(F::smallest_normalized().scalbn(F::PRECISION as ExpInt), F::ZERO)
-    }
-
-    // Implement addition, subtraction, multiplication and division based on:
-    // "Software for Doubled-Precision Floating-Point Computations",
-    // by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
-
-    fn add_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        match (self.category(), rhs.category()) {
-            (Category::Infinity, Category::Infinity) => {
-                if self.is_negative() != rhs.is_negative() {
-                    Status::INVALID_OP.and(Self::NAN.copy_sign(self))
-                } else {
-                    Status::OK.and(self)
-                }
-            }
-
-            (_, Category::Zero) | (Category::NaN, _) | (Category::Infinity, Category::Normal) => {
-                Status::OK.and(self)
-            }
-
-            (Category::Zero, _) | (_, Category::NaN | Category::Infinity) => Status::OK.and(rhs),
-
-            (Category::Normal, Category::Normal) => {
-                let mut status = Status::OK;
-                let (a, aa, c, cc) = (self.0, self.1, rhs.0, rhs.1);
-                let mut z = a;
-                z = unpack!(status|=, z.add_r(c, round));
-                if !z.is_finite() {
-                    if !z.is_infinite() {
-                        return status.and(DoubleFloat(z, F::ZERO));
-                    }
-                    status = Status::OK;
-                    let a_cmp_c = a.cmp_abs_normal(c);
-                    z = cc;
-                    z = unpack!(status|=, z.add_r(aa, round));
-                    if a_cmp_c == Ordering::Greater {
-                        // z = cc + aa + c + a;
-                        z = unpack!(status|=, z.add_r(c, round));
-                        z = unpack!(status|=, z.add_r(a, round));
-                    } else {
-                        // z = cc + aa + a + c;
-                        z = unpack!(status|=, z.add_r(a, round));
-                        z = unpack!(status|=, z.add_r(c, round));
-                    }
-                    if !z.is_finite() {
-                        return status.and(DoubleFloat(z, F::ZERO));
-                    }
-                    self.0 = z;
-                    let mut zz = aa;
-                    zz = unpack!(status|=, zz.add_r(cc, round));
-                    if a_cmp_c == Ordering::Greater {
-                        // self.1 = a - z + c + zz;
-                        self.1 = a;
-                        self.1 = unpack!(status|=, self.1.sub_r(z, round));
-                        self.1 = unpack!(status|=, self.1.add_r(c, round));
-                        self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                    } else {
-                        // self.1 = c - z + a + zz;
-                        self.1 = c;
-                        self.1 = unpack!(status|=, self.1.sub_r(z, round));
-                        self.1 = unpack!(status|=, self.1.add_r(a, round));
-                        self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                    }
-                } else {
-                    // q = a - z;
-                    let mut q = a;
-                    q = unpack!(status|=, q.sub_r(z, round));
-
-                    // zz = q + c + (a - (q + z)) + aa + cc;
-                    // Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
-                    let mut zz = q;
-                    zz = unpack!(status|=, zz.add_r(c, round));
-                    q = unpack!(status|=, q.add_r(z, round));
-                    q = unpack!(status|=, q.sub_r(a, round));
-                    q = -q;
-                    zz = unpack!(status|=, zz.add_r(q, round));
-                    zz = unpack!(status|=, zz.add_r(aa, round));
-                    zz = unpack!(status|=, zz.add_r(cc, round));
-                    if zz.is_zero() && !zz.is_negative() {
-                        return Status::OK.and(DoubleFloat(z, F::ZERO));
-                    }
-                    self.0 = z;
-                    self.0 = unpack!(status|=, self.0.add_r(zz, round));
-                    if !self.0.is_finite() {
-                        self.1 = F::ZERO;
-                        return status.and(self);
-                    }
-                    self.1 = z;
-                    self.1 = unpack!(status|=, self.1.sub_r(self.0, round));
-                    self.1 = unpack!(status|=, self.1.add_r(zz, round));
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_r(mut self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        // Interesting observation: For special categories, finding the lowest
-        // common ancestor of the following layered graph gives the correct
-        // return category:
-        //
-        //    NaN
-        //   /   \
-        // Zero  Inf
-        //   \   /
-        //   Normal
-        //
-        // e.g., NaN * NaN = NaN
-        //      Zero * Inf = NaN
-        //      Normal * Zero = Zero
-        //      Normal * Inf = Inf
-        match (self.category(), rhs.category()) {
-            (Category::NaN, _) => Status::OK.and(self),
-
-            (_, Category::NaN) => Status::OK.and(rhs),
-
-            (Category::Zero, Category::Infinity) | (Category::Infinity, Category::Zero) => {
-                Status::OK.and(Self::NAN)
-            }
-
-            (Category::Zero | Category::Infinity, _) => Status::OK.and(self),
-
-            (_, Category::Zero | Category::Infinity) => Status::OK.and(rhs),
-
-            (Category::Normal, Category::Normal) => {
-                let mut status = Status::OK;
-                let (a, b, c, d) = (self.0, self.1, rhs.0, rhs.1);
-                // t = a * c
-                let mut t = a;
-                t = unpack!(status|=, t.mul_r(c, round));
-                if !t.is_finite_non_zero() {
-                    return status.and(DoubleFloat(t, F::ZERO));
-                }
-
-                // tau = fmsub(a, c, t), that is -fmadd(-a, c, t).
-                let mut tau = a;
-                tau = unpack!(status|=, tau.mul_add_r(c, -t, round));
-                // v = a * d
-                let mut v = a;
-                v = unpack!(status|=, v.mul_r(d, round));
-                // w = b * c
-                let mut w = b;
-                w = unpack!(status|=, w.mul_r(c, round));
-                v = unpack!(status|=, v.add_r(w, round));
-                // tau += v + w
-                tau = unpack!(status|=, tau.add_r(v, round));
-                // u = t + tau
-                let mut u = t;
-                u = unpack!(status|=, u.add_r(tau, round));
-
-                self.0 = u;
-                if !u.is_finite() {
-                    self.1 = F::ZERO;
-                } else {
-                    // self.1 = (t - u) + tau
-                    t = unpack!(status|=, t.sub_r(u, round));
-                    t = unpack!(status|=, t.add_r(tau, round));
-                    self.1 = t;
-                }
-                status.and(self)
-            }
-        }
-    }
-
-    fn mul_add_r(self, multiplicand: Self, addend: Self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self)
-            .mul_add_r(Fallback::from(multiplicand), Fallback::from(addend), round)
-            .map(Self::from)
-    }
-
-    fn div_r(self, rhs: Self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self).div_r(Fallback::from(rhs), round).map(Self::from)
-    }
-
-    fn c_fmod(self, rhs: Self) -> StatusAnd<Self> {
-        Fallback::from(self).c_fmod(Fallback::from(rhs)).map(Self::from)
-    }
-
-    fn round_to_integral(self, round: Round) -> StatusAnd<Self> {
-        Fallback::from(self).round_to_integral(round).map(Self::from)
-    }
-
-    fn next_up(self) -> StatusAnd<Self> {
-        Fallback::from(self).next_up().map(Self::from)
-    }
-
-    fn from_bits(input: u128) -> Self {
-        let (a, b) = (input, input >> F::BITS);
-        DoubleFloat(F::from_bits(a & ((1 << F::BITS) - 1)), F::from_bits(b & ((1 << F::BITS) - 1)))
-    }
-
-    fn from_u128_r(input: u128, round: Round) -> StatusAnd<Self> {
-        Fallback::from_u128_r(input, round).map(Self::from)
-    }
-
-    fn from_str_r(s: &str, round: Round) -> Result<StatusAnd<Self>, ParseError> {
-        Fallback::from_str_r(s, round).map(|r| r.map(Self::from))
-    }
-
-    fn to_bits(self) -> u128 {
-        self.0.to_bits() | (self.1.to_bits() << F::BITS)
-    }
-
-    fn to_u128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd<u128> {
-        Fallback::from(self).to_u128_r(width, round, is_exact)
-    }
-
-    fn cmp_abs_normal(self, rhs: Self) -> Ordering {
-        self.0.cmp_abs_normal(rhs.0).then_with(|| {
-            let result = self.1.cmp_abs_normal(rhs.1);
-            if result != Ordering::Equal {
-                let against = self.0.is_negative() ^ self.1.is_negative();
-                let rhs_against = rhs.0.is_negative() ^ rhs.1.is_negative();
-                (!against)
-                    .cmp(&!rhs_against)
-                    .then_with(|| if against { result.reverse() } else { result })
-            } else {
-                result
-            }
-        })
-    }
-
-    fn bitwise_eq(self, rhs: Self) -> bool {
-        self.0.bitwise_eq(rhs.0) && self.1.bitwise_eq(rhs.1)
-    }
-
-    fn is_negative(self) -> bool {
-        self.0.is_negative()
-    }
-
-    fn is_denormal(self) -> bool {
-        self.category() == Category::Normal
-            && (self.0.is_denormal() || self.0.is_denormal() ||
-          // (double)(Hi + Lo) == Hi defines a normal number.
-          !(self.0 + self.1).value.bitwise_eq(self.0))
-    }
-
-    fn is_signaling(self) -> bool {
-        self.0.is_signaling()
-    }
-
-    fn category(self) -> Category {
-        self.0.category()
-    }
-
-    fn get_exact_inverse(self) -> Option<Self> {
-        Fallback::from(self).get_exact_inverse().map(Self::from)
-    }
-
-    fn ilogb(self) -> ExpInt {
-        self.0.ilogb()
-    }
-
-    fn scalbn_r(self, exp: ExpInt, round: Round) -> Self {
-        DoubleFloat(self.0.scalbn_r(exp, round), self.1.scalbn_r(exp, round))
-    }
-
-    fn frexp_r(self, exp: &mut ExpInt, round: Round) -> Self {
-        let a = self.0.frexp_r(exp, round);
-        let mut b = self.1;
-        if self.category() == Category::Normal {
-            b = b.scalbn_r(-*exp, round);
-        }
-        DoubleFloat(a, b)
-    }
-}
diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs
deleted file mode 100644
index f8fac0c..0000000
--- a/compiler/rustc_apfloat/tests/ieee.rs
+++ /dev/null
@@ -1,3301 +0,0 @@
-// ignore-tidy-filelength
-
-use rustc_apfloat::ieee::{Double, Half, Quad, Single, X87DoubleExtended};
-use rustc_apfloat::unpack;
-use rustc_apfloat::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
-use rustc_apfloat::{Float, FloatConvert, ParseError, Round, Status};
-
-trait SingleExt {
-    fn from_f32(input: f32) -> Self;
-    fn to_f32(self) -> f32;
-}
-
-impl SingleExt for Single {
-    fn from_f32(input: f32) -> Self {
-        Self::from_bits(input.to_bits() as u128)
-    }
-
-    fn to_f32(self) -> f32 {
-        f32::from_bits(self.to_bits() as u32)
-    }
-}
-
-trait DoubleExt {
-    fn from_f64(input: f64) -> Self;
-    fn to_f64(self) -> f64;
-}
-
-impl DoubleExt for Double {
-    fn from_f64(input: f64) -> Self {
-        Self::from_bits(input.to_bits() as u128)
-    }
-
-    fn to_f64(self) -> f64 {
-        f64::from_bits(self.to_bits() as u64)
-    }
-}
-
-#[test]
-fn is_signaling() {
-    // We test qNaN, -qNaN, +sNaN, -sNaN with and without payloads.
-    let payload = 4;
-    assert!(!Single::qnan(None).is_signaling());
-    assert!(!(-Single::qnan(None)).is_signaling());
-    assert!(!Single::qnan(Some(payload)).is_signaling());
-    assert!(!(-Single::qnan(Some(payload))).is_signaling());
-    assert!(Single::snan(None).is_signaling());
-    assert!((-Single::snan(None)).is_signaling());
-    assert!(Single::snan(Some(payload)).is_signaling());
-    assert!((-Single::snan(Some(payload))).is_signaling());
-}
-
-#[test]
-fn next() {
-    // 1. Test Special Cases Values.
-    //
-    // Test all special values for nextUp and nextDown perscribed by IEEE-754R
-    // 2008. These are:
-    //   1. +inf
-    //   2. -inf
-    //   3. largest
-    //   4. -largest
-    //   5. smallest
-    //   6. -smallest
-    //   7. qNaN
-    //   8. sNaN
-    //   9. +0
-    //   10. -0
-
-    let mut status;
-
-    // nextUp(+inf) = +inf.
-    let test = unpack!(status=, Quad::INFINITY.next_up());
-    let expected = Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+inf) = -nextUp(-inf) = -(-largest) = largest
-    let test = unpack!(status=, Quad::INFINITY.next_down());
-    let expected = Quad::largest();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-inf) = -largest
-    let test = unpack!(status=, (-Quad::INFINITY).next_up());
-    let expected = -Quad::largest();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-inf) = -nextUp(+inf) = -(+inf) = -inf.
-    let test = unpack!(status=, (-Quad::INFINITY).next_down());
-    let expected = -Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(largest) = +inf
-    let test = unpack!(status=, Quad::largest().next_up());
-    let expected = Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && !test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(largest) = -nextUp(-largest)
-    //                        = -(-largest + inc)
-    //                        = largest - inc.
-    let test = unpack!(status=, Quad::largest().next_down());
-    let expected = "0x1.fffffffffffffffffffffffffffep+16383".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_infinite() && !test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-largest) = -largest + inc.
-    let test = unpack!(status=, (-Quad::largest()).next_up());
-    let expected = "-0x1.fffffffffffffffffffffffffffep+16383".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-largest) = -nextUp(largest) = -(inf) = -inf.
-    let test = unpack!(status=, (-Quad::largest()).next_down());
-    let expected = -Quad::INFINITY;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_infinite() && test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(smallest) = smallest + inc.
-    let test = unpack!(status=, "0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x0.0000000000000000000000000002p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(smallest) = -nextUp(-smallest) = -(-0) = +0.
-    let test = unpack!(status=, "0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = Quad::ZERO;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_pos_zero());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-smallest) = -0.
-    let test = unpack!(status=, "-0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = -Quad::ZERO;
-    assert_eq!(status, Status::OK);
-    assert!(test.is_neg_zero());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-smallest) = -nextUp(smallest) = -smallest - inc.
-    let test = unpack!(status=, "-0x0.0000000000000000000000000001p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x0.0000000000000000000000000002p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(qNaN) = qNaN
-    let test = unpack!(status=, Quad::qnan(None).next_up());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(qNaN) = qNaN
-    let test = unpack!(status=, Quad::qnan(None).next_down());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(sNaN) = qNaN
-    let test = unpack!(status=, Quad::snan(None).next_up());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::INVALID_OP);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(sNaN) = qNaN
-    let test = unpack!(status=, Quad::snan(None).next_down());
-    let expected = Quad::qnan(None);
-    assert_eq!(status, Status::INVALID_OP);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+0) = +smallest
-    let test = unpack!(status=, Quad::ZERO.next_up());
-    let expected = Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+0) = -nextUp(-0) = -smallest
-    let test = unpack!(status=, Quad::ZERO.next_down());
-    let expected = -Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-0) = +smallest
-    let test = unpack!(status=, (-Quad::ZERO).next_up());
-    let expected = Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-0) = -nextUp(0) = -smallest
-    let test = unpack!(status=, (-Quad::ZERO).next_down());
-    let expected = -Quad::SMALLEST;
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 2. Binade Boundary Tests.
-
-    // 2a. Test denormal <-> normal binade boundaries.
-    //     * nextUp(+Largest Denormal) -> +Smallest Normal.
-    //     * nextDown(-Largest Denormal) -> -Smallest Normal.
-    //     * nextUp(-Smallest Normal) -> -Largest Denormal.
-    //     * nextDown(+Smallest Normal) -> +Largest Denormal.
-
-    // nextUp(+Largest Denormal) -> +Smallest Normal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.0000000000000000000000000000p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Largest Denormal) -> -Smallest Normal.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.0000000000000000000000000000p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Smallest Normal) -> -Largest Denormal.
-    let test = unpack!(status=, "-0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Smallest Normal) -> +Largest Denormal.
-    let test = unpack!(status=, "+0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "+0x0.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    // 2b. Test normal <-> normal binade boundaries.
-    //     * nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
-    //     * nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
-    //     * nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
-    //     * nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
-
-    // nextUp(-Normal Binade Boundary) -> -Normal Binade Boundary + 1.
-    let test = unpack!(status=, "-0x1p+1".parse::<Quad>().unwrap().next_up());
-    let expected = "-0x1.ffffffffffffffffffffffffffffp+0".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Normal Binade Boundary) -> +Normal Binade Boundary - 1.
-    let test = unpack!(status=, "0x1p+1".parse::<Quad>().unwrap().next_down());
-    let expected = "0x1.ffffffffffffffffffffffffffffp+0".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Normal Binade Boundary - 1) -> +Normal Binade Boundary.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffffffffp+0"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1p+1".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Normal Binade Boundary + 1) -> -Normal Binade Boundary.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffffffffp+0"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1p+1".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 2c. Test using next at binade boundaries with a direction away from the
-    // binade boundary. Away from denormal <-> normal boundaries.
-    //
-    // This is to make sure that even though we are at a binade boundary, since
-    // we are rounding away, we do not trigger the binade boundary code. Thus we
-    // test:
-    //   * nextUp(-Largest Denormal) -> -Largest Denormal + inc.
-    //   * nextDown(+Largest Denormal) -> +Largest Denormal - inc.
-    //   * nextUp(+Smallest Normal) -> +Smallest Normal + inc.
-    //   * nextDown(-Smallest Normal) -> -Smallest Normal - inc.
-
-    // nextUp(-Largest Denormal) -> -Largest Denormal + inc.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.fffffffffffffffffffffffffffep-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Largest Denormal) -> +Largest Denormal - inc.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x0.fffffffffffffffffffffffffffep-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Smallest Normal) -> +Smallest Normal + inc.
-    let test = unpack!(status=, "0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Smallest Normal) -> -Smallest Normal - inc.
-    let test = unpack!(status=, "-0x1.0000000000000000000000000000p-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // 2d. Test values which cause our exponent to go to min exponent. This
-    // is to ensure that guards in the code to check for min exponent
-    // trigger properly.
-    //     * nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
-    //     * nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
-    //         -0x1p-16381
-    //     * nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16382
-    //     * nextDown(0x1p-16382) -> 0x1.ffffffffffffffffffffffffffffp-16382
-
-    // nextUp(-0x1p-16381) -> -0x1.ffffffffffffffffffffffffffffp-16382
-    let test = unpack!(status=, "-0x1p-16381".parse::<Quad>().unwrap().next_up());
-    let expected = "-0x1.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-0x1.ffffffffffffffffffffffffffffp-16382) ->
-    //         -0x1p-16381
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1p-16381".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(0x1.ffffffffffffffffffffffffffffp-16382) -> 0x1p-16381
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffffffffp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1p-16381".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(0x1p-16381) -> 0x1.ffffffffffffffffffffffffffffp-16382
-    let test = unpack!(status=, "0x1p-16381".parse::<Quad>().unwrap().next_down());
-    let expected = "0x1.ffffffffffffffffffffffffffffp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.bitwise_eq(expected));
-
-    // 3. Now we test both denormal/normal computation which will not cause us
-    // to go across binade boundaries. Specifically we test:
-    //   * nextUp(+Denormal) -> +Denormal.
-    //   * nextDown(+Denormal) -> +Denormal.
-    //   * nextUp(-Denormal) -> -Denormal.
-    //   * nextDown(-Denormal) -> -Denormal.
-    //   * nextUp(+Normal) -> +Normal.
-    //   * nextDown(+Normal) -> +Normal.
-    //   * nextUp(-Normal) -> -Normal.
-    //   * nextDown(-Normal) -> -Normal.
-
-    // nextUp(+Denormal) -> +Denormal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x0.ffffffffffffffffffffffff000dp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Denormal) -> +Denormal.
-    let test = unpack!(status=, "0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x0.ffffffffffffffffffffffff000bp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Denormal) -> -Denormal.
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x0.ffffffffffffffffffffffff000bp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Denormal) -> -Denormal
-    let test = unpack!(status=, "-0x0.ffffffffffffffffffffffff000cp-16382"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x0.ffffffffffffffffffffffff000dp-16382".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(+Normal) -> +Normal.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "0x1.ffffffffffffffffffffffff000dp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(+Normal) -> +Normal.
-    let test = unpack!(status=, "0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "0x1.ffffffffffffffffffffffff000bp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextUp(-Normal) -> -Normal.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_up());
-    let expected = "-0x1.ffffffffffffffffffffffff000bp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-
-    // nextDown(-Normal) -> -Normal.
-    let test = unpack!(status=, "-0x1.ffffffffffffffffffffffff000cp-16000"
-        .parse::<Quad>()
-        .unwrap()
-        .next_down());
-    let expected = "-0x1.ffffffffffffffffffffffff000dp-16000".parse::<Quad>().unwrap();
-    assert_eq!(status, Status::OK);
-    assert!(!test.is_denormal());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn fma() {
-    {
-        let mut f1 = Single::from_f32(14.5);
-        let f2 = Single::from_f32(-14.5);
-        let f3 = Single::from_f32(225.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert_eq!(14.75, f1.to_f32());
-    }
-
-    {
-        let val2 = Single::from_f32(2.0);
-        let mut f1 = Single::from_f32(1.17549435e-38);
-        let mut f2 = Single::from_f32(1.17549435e-38);
-        f1 /= val2;
-        f2 /= val2;
-        let f3 = Single::from_f32(12.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert_eq!(12.0, f1.to_f32());
-    }
-
-    // Test for correct zero sign when answer is exactly zero.
-    // fma(1.0, -1.0, 1.0) -> +ve 0.
-    {
-        let mut f1 = Double::from_f64(1.0);
-        let f2 = Double::from_f64(-1.0);
-        let f3 = Double::from_f64(1.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(!f1.is_negative() && f1.is_zero());
-    }
-
-    // Test for correct zero sign when answer is exactly zero and rounding towards
-    // negative.
-    // fma(1.0, -1.0, 1.0) -> +ve 0.
-    {
-        let mut f1 = Double::from_f64(1.0);
-        let f2 = Double::from_f64(-1.0);
-        let f3 = Double::from_f64(1.0);
-        f1 = f1.mul_add_r(f2, f3, Round::TowardNegative).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test for correct (in this case -ve) sign when adding like signed zeros.
-    // Test fma(0.0, -0.0, -0.0) -> -ve 0.
-    {
-        let mut f1 = Double::from_f64(0.0);
-        let f2 = Double::from_f64(-0.0);
-        let f3 = Double::from_f64(-0.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test -ve sign preservation when small negative results underflow.
-    {
-        let mut f1 = "-0x1p-1074".parse::<Double>().unwrap();
-        let f2 = "+0x1p-1074".parse::<Double>().unwrap();
-        let f3 = Double::from_f64(0.0);
-        f1 = f1.mul_add(f2, f3).value;
-        assert!(f1.is_negative() && f1.is_zero());
-    }
-
-    // Test x87 extended precision case from https://llvm.org/PR20728.
-    {
-        let mut m1 = X87DoubleExtended::from_u128(1).value;
-        let m2 = X87DoubleExtended::from_u128(1).value;
-        let a = X87DoubleExtended::from_u128(3).value;
-
-        let mut loses_info = false;
-        m1 = m1.mul_add(m2, a).value;
-        let r: Single = m1.convert(&mut loses_info).value;
-        assert!(!loses_info);
-        assert_eq!(4.0, r.to_f32());
-    }
-}
-
-#[test]
-fn issue_69532() {
-    let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
-    let mut loses_info = false;
-    let sta = f.convert(&mut loses_info);
-    let r: Single = sta.value;
-    assert!(loses_info);
-    assert!(r.is_nan());
-    assert_eq!(sta.status, Status::INVALID_OP);
-}
-
-#[test]
-fn min_num() {
-    let f1 = Double::from_f64(1.0);
-    let f2 = Double::from_f64(2.0);
-    let nan = Double::NAN;
-
-    assert_eq!(1.0, f1.min(f2).to_f64());
-    assert_eq!(1.0, f2.min(f1).to_f64());
-    assert_eq!(1.0, f1.min(nan).to_f64());
-    assert_eq!(1.0, nan.min(f1).to_f64());
-}
-
-#[test]
-fn max_num() {
-    let f1 = Double::from_f64(1.0);
-    let f2 = Double::from_f64(2.0);
-    let nan = Double::NAN;
-
-    assert_eq!(2.0, f1.max(f2).to_f64());
-    assert_eq!(2.0, f2.max(f1).to_f64());
-    assert_eq!(1.0, f1.max(nan).to_f64());
-    assert_eq!(1.0, nan.max(f1).to_f64());
-}
-
-#[test]
-fn denormal() {
-    // Test single precision
-    {
-        assert!(!Single::from_f32(0.0).is_denormal());
-
-        let mut t = "1.17549435082228750797e-38".parse::<Single>().unwrap();
-        assert!(!t.is_denormal());
-
-        let val2 = Single::from_f32(2.0e0);
-        t /= val2;
-        assert!(t.is_denormal());
-    }
-
-    // Test double precision
-    {
-        assert!(!Double::from_f64(0.0).is_denormal());
-
-        let mut t = "2.22507385850720138309e-308".parse::<Double>().unwrap();
-        assert!(!t.is_denormal());
-
-        let val2 = Double::from_f64(2.0e0);
-        t /= val2;
-        assert!(t.is_denormal());
-    }
-
-    // Test Intel double-ext
-    {
-        assert!(!X87DoubleExtended::from_u128(0).value.is_denormal());
-
-        let mut t = "3.36210314311209350626e-4932".parse::<X87DoubleExtended>().unwrap();
-        assert!(!t.is_denormal());
-
-        t /= X87DoubleExtended::from_u128(2).value;
-        assert!(t.is_denormal());
-    }
-
-    // Test quadruple precision
-    {
-        assert!(!Quad::from_u128(0).value.is_denormal());
-
-        let mut t = "3.36210314311209350626267781732175260e-4932".parse::<Quad>().unwrap();
-        assert!(!t.is_denormal());
-
-        t /= Quad::from_u128(2).value;
-        assert!(t.is_denormal());
-    }
-}
-
-#[test]
-fn decimal_strings_without_null_terminators() {
-    // Make sure that we can parse strings without null terminators.
-    // rdar://14323230.
-    let val = "0.00"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.01"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.09"[..3].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.0);
-    let val = "0.095"[..4].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.09);
-    let val = "0.00e+3"[..7].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.00);
-    let val = "0e+3"[..4].parse::<Double>().unwrap();
-    assert_eq!(val.to_f64(), 0.00);
-}
-
-#[test]
-fn from_zero_decimal_string() {
-    assert_eq!(0.0, "0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "00000.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+00000.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-00000.".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.00000".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0000.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0000.00000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0000.00000".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_decimal_single_exponent_string() {
-    assert_eq!(0.0, "0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, ".0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-.0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0.0e-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0.0e-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "000.0000e1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+000.0000e+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-000.0000e+1".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_decimal_large_exponent_string() {
-    assert_eq!(0.0, "0e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e+1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e+1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e+1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0e-1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0e-1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0e-1234".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "000.0000e1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "000.0000e-1234".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_zero_hexadecimal_string() {
-    assert_eq!(0.0, "0x0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x.0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x0.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "+0x0.0p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0.0p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.0, "0x00000.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0000.00000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x.00000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0.p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.0, "-0x0p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x00000.p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0000.00000p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x.00000p1234".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.0, "0x0.p1234".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_decimal_string() {
-    assert_eq!(1.0, "1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "2.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.5, ".5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "1.0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-4.0, "-4.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.5, "-.5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.5, "-1.5".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e12, "1.25e12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e+12, "1.25e+12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.25e-12, "1.25e-12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1024.0, "1024.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1024.05, "1024.05000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.05, ".05000".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "2.".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e2, "2.e2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e+2, "2.e+2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0e-2, "2.e-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e2, "002.05000e2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e+2, "002.05000e+2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e-2, "002.05000e-2".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e12, "002.05000e12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e+12, "002.05000e+12".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.05e-12, "002.05000e-12".parse::<Double>().unwrap().to_f64());
-
-    // These are "carefully selected" to overflow the fast log-base
-    // calculations in the implementation.
-    assert!("99e99999".parse::<Double>().unwrap().is_infinite());
-    assert!("-99e99999".parse::<Double>().unwrap().is_infinite());
-    assert!("1e-99999".parse::<Double>().unwrap().is_pos_zero());
-    assert!("-1e-99999".parse::<Double>().unwrap().is_neg_zero());
-
-    assert_eq!(2.71828, "2.71828".parse::<Double>().unwrap().to_f64());
-}
-
-#[test]
-fn from_hexadecimal_string() {
-    assert_eq!(1.0, "0x1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0, "0x1p+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p+0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p+0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0, "0x1p-0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "+0x1p-0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-1.0, "-0x1p-0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2.0, "0x1p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "+0x1p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-0x1p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2.0, "0x1p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2.0, "+0x1p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2.0, "-0x1p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.5, "0x1p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.5, "+0x1p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.5, "-0x1p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(3.0, "0x1.8p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(3.0, "+0x1.8p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-3.0, "-0x1.8p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(3.0, "0x1.8p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(3.0, "+0x1.8p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-3.0, "-0x1.8p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.75, "0x1.8p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.75, "+0x1.8p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.75, "-0x1.8p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000.000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000.000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000.000p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000.000p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2048.0, "0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2048.0, "+0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2048.0, "-0x1000.000p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000p1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000p1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(8192.0, "0x1000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(8192.0, "+0x1000p+1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-8192.0, "-0x1000p+1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(2048.0, "0x1000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(2048.0, "+0x1000p-1".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-2048.0, "-0x1000p-1".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(16384.0, "0x10p10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(16384.0, "+0x10p10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-16384.0, "-0x10p10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(16384.0, "0x10p+10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(16384.0, "+0x10p+10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-16384.0, "-0x10p+10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(0.015625, "0x10p-10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(0.015625, "+0x10p-10".parse::<Double>().unwrap().to_f64());
-    assert_eq!(-0.015625, "-0x10p-10".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(1.0625, "0x1.1p0".parse::<Double>().unwrap().to_f64());
-    assert_eq!(1.0, "0x1p0".parse::<Double>().unwrap().to_f64());
-
-    assert_eq!(
-        "0x1p-150".parse::<Double>().unwrap().to_f64(),
-        "+0x800000000000000001.p-221".parse::<Double>().unwrap().to_f64()
-    );
-    assert_eq!(
-        2251799813685248.5,
-        "0x80000000000004000000.010p-28".parse::<Double>().unwrap().to_f64()
-    );
-}
-
-#[test]
-fn to_string() {
-    let to_string = |d: f64, precision: usize, width: usize| {
-        let x = Double::from_f64(d);
-        if precision == 0 {
-            format!("{:1$}", x, width)
-        } else {
-            format!("{:2$.1$}", x, precision, width)
-        }
-    };
-    assert_eq!("10", to_string(10.0, 6, 3));
-    assert_eq!("1.0E+1", to_string(10.0, 6, 0));
-    assert_eq!("10100", to_string(1.01E+4, 5, 2));
-    assert_eq!("1.01E+4", to_string(1.01E+4, 4, 2));
-    assert_eq!("1.01E+4", to_string(1.01E+4, 5, 1));
-    assert_eq!("0.0101", to_string(1.01E-2, 5, 2));
-    assert_eq!("0.0101", to_string(1.01E-2, 4, 2));
-    assert_eq!("1.01E-2", to_string(1.01E-2, 5, 1));
-    assert_eq!("0.78539816339744828", to_string(0.78539816339744830961, 0, 3));
-    assert_eq!("4.9406564584124654E-324", to_string(4.9406564584124654e-324, 0, 3));
-    assert_eq!("873.18340000000001", to_string(873.1834, 0, 1));
-    assert_eq!("8.7318340000000001E+2", to_string(873.1834, 0, 0));
-    assert_eq!("1.7976931348623157E+308", to_string(1.7976931348623157E+308, 0, 0));
-
-    let to_string = |d: f64, precision: usize, width: usize| {
-        let x = Double::from_f64(d);
-        if precision == 0 {
-            format!("{:#1$}", x, width)
-        } else {
-            format!("{:#2$.1$}", x, precision, width)
-        }
-    };
-    assert_eq!("10", to_string(10.0, 6, 3));
-    assert_eq!("1.000000e+01", to_string(10.0, 6, 0));
-    assert_eq!("10100", to_string(1.01E+4, 5, 2));
-    assert_eq!("1.0100e+04", to_string(1.01E+4, 4, 2));
-    assert_eq!("1.01000e+04", to_string(1.01E+4, 5, 1));
-    assert_eq!("0.0101", to_string(1.01E-2, 5, 2));
-    assert_eq!("0.0101", to_string(1.01E-2, 4, 2));
-    assert_eq!("1.01000e-02", to_string(1.01E-2, 5, 1));
-    assert_eq!("0.78539816339744828", to_string(0.78539816339744830961, 0, 3));
-    assert_eq!("4.94065645841246540e-324", to_string(4.9406564584124654e-324, 0, 3));
-    assert_eq!("873.18340000000001", to_string(873.1834, 0, 1));
-    assert_eq!("8.73183400000000010e+02", to_string(873.1834, 0, 0));
-    assert_eq!("1.79769313486231570e+308", to_string(1.7976931348623157E+308, 0, 0));
-}
-
-#[test]
-fn to_integer() {
-    let mut is_exact = false;
-
-    assert_eq!(
-        Status::OK.and(10),
-        "10".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(0),
-        "-10".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(31),
-        "32".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INEXACT.and(7),
-        "7.9".parse::<Double>().unwrap().to_u128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::OK.and(-10),
-        "-10".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(-16),
-        "-17".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-
-    assert_eq!(
-        Status::INVALID_OP.and(15),
-        "16".parse::<Double>().unwrap().to_i128_r(5, Round::TowardZero, &mut is_exact,)
-    );
-    assert!(!is_exact);
-}
-
-#[test]
-fn nan() {
-    fn nanbits<T: Float>(signaling: bool, negative: bool, fill: u128) -> u128 {
-        let x = if signaling { T::snan(Some(fill)) } else { T::qnan(Some(fill)) };
-        if negative { (-x).to_bits() } else { x.to_bits() }
-    }
-
-    assert_eq!(0x7fc00000, nanbits::<Single>(false, false, 0));
-    assert_eq!(0xffc00000, nanbits::<Single>(false, true, 0));
-    assert_eq!(0x7fc0ae72, nanbits::<Single>(false, false, 0xae72));
-    assert_eq!(0x7fffae72, nanbits::<Single>(false, false, 0xffffae72));
-    assert_eq!(0x7fa00000, nanbits::<Single>(true, false, 0));
-    assert_eq!(0xffa00000, nanbits::<Single>(true, true, 0));
-    assert_eq!(0x7f80ae72, nanbits::<Single>(true, false, 0xae72));
-    assert_eq!(0x7fbfae72, nanbits::<Single>(true, false, 0xffffae72));
-
-    assert_eq!(0x7ff8000000000000, nanbits::<Double>(false, false, 0));
-    assert_eq!(0xfff8000000000000, nanbits::<Double>(false, true, 0));
-    assert_eq!(0x7ff800000000ae72, nanbits::<Double>(false, false, 0xae72));
-    assert_eq!(0x7fffffffffffae72, nanbits::<Double>(false, false, 0xffffffffffffae72));
-    assert_eq!(0x7ff4000000000000, nanbits::<Double>(true, false, 0));
-    assert_eq!(0xfff4000000000000, nanbits::<Double>(true, true, 0));
-    assert_eq!(0x7ff000000000ae72, nanbits::<Double>(true, false, 0xae72));
-    assert_eq!(0x7ff7ffffffffae72, nanbits::<Double>(true, false, 0xffffffffffffae72));
-}
-
-#[test]
-fn string_decimal_death() {
-    assert_eq!("".parse::<Double>(), Err(ParseError("Invalid string length")));
-    assert_eq!("+".parse::<Double>(), Err(ParseError("String has no digits")));
-    assert_eq!("-".parse::<Double>(), Err(ParseError("String has no digits")));
-
-    assert_eq!("\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\02".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1\02e1".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("1e\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("1e1\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("1e1\02".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("1.0f".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-
-    assert_eq!("..".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("..0".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("1.0.0".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-}
-
-#[test]
-fn string_decimal_significand_death() {
-    assert_eq!(".".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!(".e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.e1".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!(".e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+.e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-.e".parse::<Double>(), Err(ParseError("Significand has no digits")));
-}
-
-#[test]
-fn string_decimal_exponent_death() {
-    assert_eq!("1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1.e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!(".1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-1.1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!(".1e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!(".1e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!(".1e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("1.0e".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1.0e+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("1.0e-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-}
-
-#[test]
-fn string_hexadecimal_death() {
-    assert_eq!("0x".parse::<Double>(), Err(ParseError("Invalid string")));
-    assert_eq!("+0x".parse::<Double>(), Err(ParseError("Invalid string")));
-    assert_eq!("-0x".parse::<Double>(), Err(ParseError("Invalid string")));
-
-    assert_eq!("0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0.".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("+0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-    assert_eq!("-0x0.0".parse::<Double>(), Err(ParseError("Hex strings require an exponent")));
-
-    assert_eq!("0x\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\0".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\02".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1\02p1".parse::<Double>(), Err(ParseError("Invalid character in significand")));
-    assert_eq!("0x1p\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("0x1p1\0".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-    assert_eq!("0x1p1\02".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("0x1p0f".parse::<Double>(), Err(ParseError("Invalid character in exponent")));
-
-    assert_eq!("0x..p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("0x..0p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-    assert_eq!("0x1.0.0p1".parse::<Double>(), Err(ParseError("String contains multiple dots")));
-}
-
-#[test]
-fn string_hexadecimal_significand_death() {
-    assert_eq!("0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0xp-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p+".parse::<Double>(), Err(ParseError("Significand has no digits")));
-
-    assert_eq!("0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("+0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-    assert_eq!("-0x.p-".parse::<Double>(), Err(ParseError("Significand has no digits")));
-}
-
-#[test]
-fn string_hexadecimal_exponent_death() {
-    assert_eq!("0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p+".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-
-    assert_eq!("0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("+0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-    assert_eq!("-0x1.1p-".parse::<Double>(), Err(ParseError("Exponent has no digits")));
-}
-
-#[test]
-fn exact_inverse() {
-    // Trivial operation.
-    assert!(Double::from_f64(2.0).get_exact_inverse().unwrap().bitwise_eq(Double::from_f64(0.5)));
-    assert!(Single::from_f32(2.0).get_exact_inverse().unwrap().bitwise_eq(Single::from_f32(0.5)));
-    assert!(
-        "2.0"
-            .parse::<Quad>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<Quad>().unwrap())
-    );
-    assert!(
-        "2.0"
-            .parse::<X87DoubleExtended>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<X87DoubleExtended>().unwrap())
-    );
-
-    // FLT_MIN
-    assert!(
-        Single::from_f32(1.17549435e-38)
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq(Single::from_f32(8.5070592e+37))
-    );
-
-    // Large float, inverse is a denormal.
-    assert!(Single::from_f32(1.7014118e38).get_exact_inverse().is_none());
-    // Zero
-    assert!(Double::from_f64(0.0).get_exact_inverse().is_none());
-    // Denormalized float
-    assert!(Single::from_f32(1.40129846e-45).get_exact_inverse().is_none());
-}
-
-#[test]
-fn round_to_integral() {
-    let t = Double::from_f64(-0.5);
-    assert_eq!(-0.0, t.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(-1.0, t.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(-0.0, t.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(-0.0, t.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let s = Double::from_f64(3.14);
-    assert_eq!(3.0, s.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(3.0, s.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(4.0, s.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(3.0, s.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let r = Double::largest();
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardZero).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardNegative).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::TowardPositive).value.to_f64());
-    assert_eq!(r.to_f64(), r.round_to_integral(Round::NearestTiesToEven).value.to_f64());
-
-    let p = Double::ZERO.round_to_integral(Round::TowardZero).value;
-    assert_eq!(0.0, p.to_f64());
-    let p = (-Double::ZERO).round_to_integral(Round::TowardZero).value;
-    assert_eq!(-0.0, p.to_f64());
-    let p = Double::NAN.round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_nan());
-    let p = Double::INFINITY.round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_infinite() && p.to_f64() > 0.0);
-    let p = (-Double::INFINITY).round_to_integral(Round::TowardZero).value;
-    assert!(p.to_f64().is_infinite() && p.to_f64() < 0.0);
-}
-
-#[test]
-fn is_integer() {
-    let t = Double::from_f64(-0.0);
-    assert!(t.is_integer());
-    let t = Double::from_f64(3.14159);
-    assert!(!t.is_integer());
-    let t = Double::NAN;
-    assert!(!t.is_integer());
-    let t = Double::INFINITY;
-    assert!(!t.is_integer());
-    let t = -Double::INFINITY;
-    assert!(!t.is_integer());
-    let t = Double::largest();
-    assert!(t.is_integer());
-}
-
-#[test]
-fn largest() {
-    assert_eq!(3.402823466e+38, Single::largest().to_f32());
-    assert_eq!(1.7976931348623158e+308, Double::largest().to_f64());
-}
-
-#[test]
-fn smallest() {
-    let test = Single::SMALLEST;
-    let expected = "0x0.000002p-126".parse::<Single>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Single::SMALLEST;
-    let expected = "-0x0.000002p-126".parse::<Single>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = Quad::SMALLEST;
-    let expected = "0x0.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Quad::SMALLEST;
-    let expected = "-0x0.0000000000000000000000000001p-16382".parse::<Quad>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn smallest_normalized() {
-    let test = Single::smallest_normalized();
-    let expected = "0x1p-126".parse::<Single>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Single::smallest_normalized();
-    let expected = "-0x1p-126".parse::<Single>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = Quad::smallest_normalized();
-    let expected = "0x1p-16382".parse::<Quad>().unwrap();
-    assert!(!test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-
-    let test = -Quad::smallest_normalized();
-    let expected = "-0x1p-16382".parse::<Quad>().unwrap();
-    assert!(test.is_negative());
-    assert!(test.is_finite_non_zero());
-    assert!(!test.is_denormal());
-    assert!(test.bitwise_eq(expected));
-}
-
-#[test]
-fn zero() {
-    assert_eq!(0.0, Single::from_f32(0.0).to_f32());
-    assert_eq!(-0.0, Single::from_f32(-0.0).to_f32());
-    assert!(Single::from_f32(-0.0).is_negative());
-
-    assert_eq!(0.0, Double::from_f64(0.0).to_f64());
-    assert_eq!(-0.0, Double::from_f64(-0.0).to_f64());
-    assert!(Double::from_f64(-0.0).is_negative());
-
-    fn test<T: Float>(sign: bool, bits: u128) {
-        let test = if sign { -T::ZERO } else { T::ZERO };
-        let pattern = if sign { "-0x0p+0" } else { "0x0p+0" };
-        let expected = pattern.parse::<T>().unwrap();
-        assert!(test.is_zero());
-        assert_eq!(sign, test.is_negative());
-        assert!(test.bitwise_eq(expected));
-        assert_eq!(bits, test.to_bits());
-    }
-    test::<Half>(false, 0);
-    test::<Half>(true, 0x8000);
-    test::<Single>(false, 0);
-    test::<Single>(true, 0x80000000);
-    test::<Double>(false, 0);
-    test::<Double>(true, 0x8000000000000000);
-    test::<Quad>(false, 0);
-    test::<Quad>(true, 0x8000000000000000_0000000000000000);
-    test::<X87DoubleExtended>(false, 0);
-    test::<X87DoubleExtended>(true, 0x8000_0000000000000000);
-}
-
-#[test]
-fn copy_sign() {
-    assert!(
-        Double::from_f64(-42.0)
-            .bitwise_eq(Double::from_f64(42.0).copy_sign(Double::from_f64(-1.0),),)
-    );
-    assert!(
-        Double::from_f64(42.0)
-            .bitwise_eq(Double::from_f64(-42.0).copy_sign(Double::from_f64(1.0),),)
-    );
-    assert!(
-        Double::from_f64(-42.0)
-            .bitwise_eq(Double::from_f64(-42.0).copy_sign(Double::from_f64(-1.0),),)
-    );
-    assert!(
-        Double::from_f64(42.0)
-            .bitwise_eq(Double::from_f64(42.0).copy_sign(Double::from_f64(1.0),),)
-    );
-}
-
-#[test]
-fn convert() {
-    let mut loses_info = false;
-    let test = "1.0".parse::<Double>().unwrap();
-    let test: Single = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f32());
-    assert!(!loses_info);
-
-    let mut test = "0x1p-53".parse::<X87DoubleExtended>().unwrap();
-    let one = "1.0".parse::<X87DoubleExtended>().unwrap();
-    test += one;
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f64());
-    assert!(loses_info);
-
-    let mut test = "0x1p-53".parse::<Quad>().unwrap();
-    let one = "1.0".parse::<Quad>().unwrap();
-    test += one;
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(1.0, test.to_f64());
-    assert!(loses_info);
-
-    let test = "0xf.fffffffp+28".parse::<X87DoubleExtended>().unwrap();
-    let test: Double = test.convert(&mut loses_info).value;
-    assert_eq!(4294967295.0, test.to_f64());
-    assert!(!loses_info);
-
-    let test = Single::qnan(None);
-    let x87_qnan = X87DoubleExtended::qnan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_qnan));
-    assert!(!loses_info);
-
-    let test = Single::snan(None);
-    let sta = test.convert(&mut loses_info);
-    let test: X87DoubleExtended = sta.value;
-    assert!(test.is_nan());
-    assert!(!test.is_signaling());
-    assert!(!loses_info);
-    assert_eq!(sta.status, Status::INVALID_OP);
-
-    let test = X87DoubleExtended::qnan(None);
-    let test: X87DoubleExtended = test.convert(&mut loses_info).value;
-    assert!(test.bitwise_eq(x87_qnan));
-    assert!(!loses_info);
-
-    let test = X87DoubleExtended::snan(None);
-    let sta = test.convert(&mut loses_info);
-    let test: X87DoubleExtended = sta.value;
-    assert!(test.is_nan());
-    assert!(!test.is_signaling());
-    assert!(!loses_info);
-    assert_eq!(sta.status, Status::INVALID_OP);
-}
-
-#[test]
-fn is_negative() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_negative());
-    let t = "-0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_negative());
-
-    assert!(!Single::INFINITY.is_negative());
-    assert!((-Single::INFINITY).is_negative());
-
-    assert!(!Single::ZERO.is_negative());
-    assert!((-Single::ZERO).is_negative());
-
-    assert!(!Single::NAN.is_negative());
-    assert!((-Single::NAN).is_negative());
-
-    assert!(!Single::snan(None).is_negative());
-    assert!((-Single::snan(None)).is_negative());
-}
-
-#[test]
-fn is_normal() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_normal());
-
-    assert!(!Single::INFINITY.is_normal());
-    assert!(!Single::ZERO.is_normal());
-    assert!(!Single::NAN.is_normal());
-    assert!(!Single::snan(None).is_normal());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_normal());
-}
-
-#[test]
-fn is_finite() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(t.is_finite());
-    assert!(!Single::INFINITY.is_finite());
-    assert!(Single::ZERO.is_finite());
-    assert!(!Single::NAN.is_finite());
-    assert!(!Single::snan(None).is_finite());
-    assert!("0x1p-149".parse::<Single>().unwrap().is_finite());
-}
-
-#[test]
-fn is_infinite() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_infinite());
-    assert!(Single::INFINITY.is_infinite());
-    assert!(!Single::ZERO.is_infinite());
-    assert!(!Single::NAN.is_infinite());
-    assert!(!Single::snan(None).is_infinite());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_infinite());
-}
-
-#[test]
-fn is_nan() {
-    let t = "0x1p+0".parse::<Single>().unwrap();
-    assert!(!t.is_nan());
-    assert!(!Single::INFINITY.is_nan());
-    assert!(!Single::ZERO.is_nan());
-    assert!(Single::NAN.is_nan());
-    assert!(Single::snan(None).is_nan());
-    assert!(!"0x1p-149".parse::<Single>().unwrap().is_nan());
-}
-
-#[test]
-fn is_finite_non_zero() {
-    // Test positive/negative normal value.
-    assert!("0x1p+0".parse::<Single>().unwrap().is_finite_non_zero());
-    assert!("-0x1p+0".parse::<Single>().unwrap().is_finite_non_zero());
-
-    // Test positive/negative denormal value.
-    assert!("0x1p-149".parse::<Single>().unwrap().is_finite_non_zero());
-    assert!("-0x1p-149".parse::<Single>().unwrap().is_finite_non_zero());
-
-    // Test +/- Infinity.
-    assert!(!Single::INFINITY.is_finite_non_zero());
-    assert!(!(-Single::INFINITY).is_finite_non_zero());
-
-    // Test +/- Zero.
-    assert!(!Single::ZERO.is_finite_non_zero());
-    assert!(!(-Single::ZERO).is_finite_non_zero());
-
-    // Test +/- qNaN. +/- don't mean anything with qNaN but paranoia can't hurt in
-    // this instance.
-    assert!(!Single::NAN.is_finite_non_zero());
-    assert!(!(-Single::NAN).is_finite_non_zero());
-
-    // Test +/- sNaN. +/- don't mean anything with sNaN but paranoia can't hurt in
-    // this instance.
-    assert!(!Single::snan(None).is_finite_non_zero());
-    assert!(!(-Single::snan(None)).is_finite_non_zero());
-}
-
-#[test]
-fn add() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_zero, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_zero, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_zero, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_zero, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_zero, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_zero, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_zero, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_zero, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_zero, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_zero, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_zero, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_zero, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (m_zero, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+1", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_normal_value, "-0x1p+1", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, p_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            p_largest_value,
-            p_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_largest_value,
-            m_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            m_largest_value,
-            p_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_largest_value,
-            m_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x1p-148", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, p_smallest_normalized, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_smallest_value, "-0x1p-148", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_normalized, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            p_smallest_normalized,
-            p_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_smallest_normalized,
-            m_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_normalized, p_smallest_value, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x1p-125", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            m_smallest_normalized,
-            p_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_smallest_normalized,
-            m_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_smallest_normalized, p_smallest_value, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x + y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn subtract() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_zero, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_zero, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_zero, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_zero, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_zero, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_zero, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (p_zero, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (m_zero, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_zero, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_zero, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_zero, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_zero, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_zero, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_zero, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_zero, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_zero, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_zero, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_normal_value, "0x1p+1", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_zero, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+1", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_zero, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_normal_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_largest_value, m_smallest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            p_largest_value,
-            p_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_largest_value,
-            m_smallest_normalized,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_zero, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_normal_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, p_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_largest_value, m_smallest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (
-            m_largest_value,
-            p_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_largest_value,
-            m_smallest_normalized,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_zero, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_smallest_value, "0x1p-148", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_normalized, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_zero, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, m_largest_value, "0x1.fffffep+127", Status::INEXACT, Category::Normal),
-        (m_smallest_value, p_smallest_value, "-0x1p-148", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, p_smallest_normalized, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_zero, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            p_smallest_normalized,
-            p_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            p_smallest_normalized,
-            m_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (p_smallest_normalized, p_smallest_value, "0x1.fffffcp-127", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "0x1.000002p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_smallest_normalized, "0x1p-125", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_zero, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, qnan, "-nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "-nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p+0", Status::INEXACT, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p+0", Status::INEXACT, Category::Normal),
-        (
-            m_smallest_normalized,
-            p_largest_value,
-            "-0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (
-            m_smallest_normalized,
-            m_largest_value,
-            "0x1.fffffep+127",
-            Status::INEXACT,
-            Category::Normal,
-        ),
-        (m_smallest_normalized, p_smallest_value, "-0x1.000002p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "-0x1.fffffcp-127", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x - y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn multiply() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-    let underflow_status = Status::UNDERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_normal_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_normal_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_normal_value, p_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_normal_value, p_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_normal_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_normal_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_normal_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_normal_value, p_smallest_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_normal_value, p_smallest_normalized, "-0x1p-126", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "0x1p-126", Status::OK, Category::Normal),
-        (p_largest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_largest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_largest_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, p_largest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_largest_value, "-inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_largest_value, m_smallest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_largest_value, p_smallest_normalized, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_largest_value, m_smallest_normalized, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_largest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_largest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_largest_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, p_largest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_largest_value, "inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_largest_value, m_smallest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_largest_value, p_smallest_normalized, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_largest_value, m_smallest_normalized, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_value, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_value, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_value, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_smallest_value, m_largest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, p_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_value, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_value, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_smallest_value, m_largest_value, "0x1.fffffep-22", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_inf, "inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, m_inf, "-inf", Status::OK, Category::Infinity),
-        (p_smallest_normalized, p_zero, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_largest_value, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_largest_value, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_inf, "-inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, m_inf, "inf", Status::OK, Category::Infinity),
-        (m_smallest_normalized, p_zero, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_zero, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_largest_value, "-0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_largest_value, "0x1.fffffep+1", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_smallest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_smallest_normalized, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x * y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn divide() {
-    // Test Special Cases against each other and normal values.
-
-    // FIXMES/NOTES:
-    // 1. Since we perform only default exception handling all operations with
-    // signaling NaNs should have a result that is a quiet NaN. Currently they
-    // return sNaN.
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let qnan = Single::NAN;
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    let overflow_status = Status::OVERFLOW | Status::INEXACT;
-    let underflow_status = Status::UNDERFLOW | Status::INEXACT;
-
-    let special_cases = [
-        (p_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (p_inf, p_zero, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_zero, "-inf", Status::OK, Category::Infinity),
-        (p_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_inf, p_normal_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_normal_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_largest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_largest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_value, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (p_inf, p_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_inf, m_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (m_inf, p_zero, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_zero, "inf", Status::OK, Category::Infinity),
-        (m_inf, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_inf, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_inf, p_normal_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_normal_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_largest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_largest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_value, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_value, "inf", Status::OK, Category::Infinity),
-        (m_inf, p_smallest_normalized, "-inf", Status::OK, Category::Infinity),
-        (m_inf, m_smallest_normalized, "inf", Status::OK, Category::Infinity),
-        (p_zero, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (p_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_zero, p_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (p_zero, p_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (p_zero, m_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (m_zero, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_zero, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_zero, p_normal_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_normal_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_largest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_largest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_value, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_value, "0x0p+0", Status::OK, Category::Zero),
-        (m_zero, p_smallest_normalized, "-0x0p+0", Status::OK, Category::Zero),
-        (m_zero, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
-        (qnan, p_inf, "nan", Status::OK, Category::NaN),
-        (qnan, m_inf, "nan", Status::OK, Category::NaN),
-        (qnan, p_zero, "nan", Status::OK, Category::NaN),
-        (qnan, m_zero, "nan", Status::OK, Category::NaN),
-        (qnan, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (qnan, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (qnan, p_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_normal_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_largest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_value, "nan", Status::OK, Category::NaN),
-        (qnan, p_smallest_normalized, "nan", Status::OK, Category::NaN),
-        (qnan, m_smallest_normalized, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (snan, p_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_inf, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_zero, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, qnan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, snan, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_normal_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_largest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_value, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, p_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-        (snan, m_smallest_normalized, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_normal_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_normal_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_normal_value, p_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, m_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_normal_value, p_largest_value, "0x1p-128", underflow_status, Category::Normal),
-        (p_normal_value, m_largest_value, "-0x1p-128", underflow_status, Category::Normal),
-        (p_normal_value, p_smallest_value, "inf", overflow_status, Category::Infinity),
-        (p_normal_value, m_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (p_normal_value, p_smallest_normalized, "0x1p+126", Status::OK, Category::Normal),
-        (p_normal_value, m_smallest_normalized, "-0x1p+126", Status::OK, Category::Normal),
-        (m_normal_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_normal_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_normal_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_normal_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_normal_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_normal_value, p_normal_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, m_normal_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_normal_value, p_largest_value, "-0x1p-128", underflow_status, Category::Normal),
-        (m_normal_value, m_largest_value, "0x1p-128", underflow_status, Category::Normal),
-        (m_normal_value, p_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (m_normal_value, m_smallest_value, "inf", overflow_status, Category::Infinity),
-        (m_normal_value, p_smallest_normalized, "-0x1p+126", Status::OK, Category::Normal),
-        (m_normal_value, m_smallest_normalized, "0x1p+126", Status::OK, Category::Normal),
-        (p_largest_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_largest_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_largest_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_largest_value, p_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, m_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (p_largest_value, p_largest_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_largest_value, m_largest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_largest_value, p_smallest_value, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (p_largest_value, p_smallest_normalized, "inf", overflow_status, Category::Infinity),
-        (p_largest_value, m_smallest_normalized, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_largest_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_largest_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_largest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_largest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_largest_value, p_normal_value, "-0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, m_normal_value, "0x1.fffffep+127", Status::OK, Category::Normal),
-        (m_largest_value, p_largest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_largest_value, m_largest_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_largest_value, p_smallest_value, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_smallest_value, "inf", overflow_status, Category::Infinity),
-        (m_largest_value, p_smallest_normalized, "-inf", overflow_status, Category::Infinity),
-        (m_largest_value, m_smallest_normalized, "inf", overflow_status, Category::Infinity),
-        (p_smallest_value, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_value, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_value, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_value, p_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, m_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (p_smallest_value, p_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, m_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_value, p_smallest_value, "0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_value, p_smallest_normalized, "0x1p-23", Status::OK, Category::Normal),
-        (p_smallest_value, m_smallest_normalized, "-0x1p-23", Status::OK, Category::Normal),
-        (m_smallest_value, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_value, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_value, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_value, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_value, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_value, p_normal_value, "-0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, m_normal_value, "0x1p-149", Status::OK, Category::Normal),
-        (m_smallest_value, p_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, m_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_value, p_smallest_value, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_value, "0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_value, p_smallest_normalized, "-0x1p-23", Status::OK, Category::Normal),
-        (m_smallest_value, m_smallest_normalized, "0x1p-23", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_inf, "0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, m_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (p_smallest_normalized, p_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_normalized, m_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (p_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (p_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (p_smallest_normalized, p_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, m_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (p_smallest_normalized, p_smallest_value, "0x1p+23", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_value, "-0x1p+23", Status::OK, Category::Normal),
-        (p_smallest_normalized, p_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
-        (p_smallest_normalized, m_smallest_normalized, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_inf, "-0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, m_inf, "0x0p+0", Status::OK, Category::Zero),
-        (m_smallest_normalized, p_zero, "-inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_normalized, m_zero, "inf", Status::DIV_BY_ZERO, Category::Infinity),
-        (m_smallest_normalized, qnan, "nan", Status::OK, Category::NaN),
-        /*
-        // See Note 1.
-        (m_smallest_normalized, snan, "nan", Status::INVALID_OP, Category::NaN),
-                */
-        (m_smallest_normalized, p_normal_value, "-0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_normal_value, "0x1p-126", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_largest_value, "-0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, m_largest_value, "0x0p+0", underflow_status, Category::Zero),
-        (m_smallest_normalized, p_smallest_value, "-0x1p+23", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_value, "0x1p+23", Status::OK, Category::Normal),
-        (m_smallest_normalized, p_smallest_normalized, "-0x1p+0", Status::OK, Category::Normal),
-        (m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
-    ];
-
-    for (x, y, e_result, e_status, e_category) in special_cases {
-        let status;
-        let result = unpack!(status=, x / y);
-        assert_eq!(status, e_status);
-        assert_eq!(result.category(), e_category);
-        assert!(result.bitwise_eq(e_result.parse::<Single>().unwrap()));
-    }
-}
-
-#[test]
-fn operator_overloads() {
-    // This is mostly testing that these operator overloads compile.
-    let one = "0x1p+0".parse::<Single>().unwrap();
-    let two = "0x2p+0".parse::<Single>().unwrap();
-    assert!(two.bitwise_eq((one + one).value));
-    assert!(one.bitwise_eq((two - one).value));
-    assert!(two.bitwise_eq((one * two).value));
-    assert!(one.bitwise_eq((two / two).value));
-}
-
-#[test]
-fn abs() {
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let p_qnan = Single::NAN;
-    let m_qnan = -Single::NAN;
-    let p_snan = Single::snan(None);
-    let m_snan = -Single::snan(None);
-    let p_normal_value = "0x1p+0".parse::<Single>().unwrap();
-    let m_normal_value = "-0x1p+0".parse::<Single>().unwrap();
-    let p_largest_value = Single::largest();
-    let m_largest_value = -Single::largest();
-    let p_smallest_value = Single::SMALLEST;
-    let m_smallest_value = -Single::SMALLEST;
-    let p_smallest_normalized = Single::smallest_normalized();
-    let m_smallest_normalized = -Single::smallest_normalized();
-
-    assert!(p_inf.bitwise_eq(p_inf.abs()));
-    assert!(p_inf.bitwise_eq(m_inf.abs()));
-    assert!(p_zero.bitwise_eq(p_zero.abs()));
-    assert!(p_zero.bitwise_eq(m_zero.abs()));
-    assert!(p_qnan.bitwise_eq(p_qnan.abs()));
-    assert!(p_qnan.bitwise_eq(m_qnan.abs()));
-    assert!(p_snan.bitwise_eq(p_snan.abs()));
-    assert!(p_snan.bitwise_eq(m_snan.abs()));
-    assert!(p_normal_value.bitwise_eq(p_normal_value.abs()));
-    assert!(p_normal_value.bitwise_eq(m_normal_value.abs()));
-    assert!(p_largest_value.bitwise_eq(p_largest_value.abs()));
-    assert!(p_largest_value.bitwise_eq(m_largest_value.abs()));
-    assert!(p_smallest_value.bitwise_eq(p_smallest_value.abs()));
-    assert!(p_smallest_value.bitwise_eq(m_smallest_value.abs()));
-    assert!(p_smallest_normalized.bitwise_eq(p_smallest_normalized.abs(),));
-    assert!(p_smallest_normalized.bitwise_eq(m_smallest_normalized.abs(),));
-}
-
-#[test]
-fn neg() {
-    let one = "1.0".parse::<Single>().unwrap();
-    let neg_one = "-1.0".parse::<Single>().unwrap();
-    let zero = Single::ZERO;
-    let neg_zero = -Single::ZERO;
-    let inf = Single::INFINITY;
-    let neg_inf = -Single::INFINITY;
-    let qnan = Single::NAN;
-    let neg_qnan = -Single::NAN;
-
-    assert!(neg_one.bitwise_eq(-one));
-    assert!(one.bitwise_eq(-neg_one));
-    assert!(neg_zero.bitwise_eq(-zero));
-    assert!(zero.bitwise_eq(-neg_zero));
-    assert!(neg_inf.bitwise_eq(-inf));
-    assert!(inf.bitwise_eq(-neg_inf));
-    assert!(neg_inf.bitwise_eq(-inf));
-    assert!(inf.bitwise_eq(-neg_inf));
-    assert!(neg_qnan.bitwise_eq(-qnan));
-    assert!(qnan.bitwise_eq(-neg_qnan));
-}
-
-#[test]
-fn ilogb() {
-    assert_eq!(-1074, Double::SMALLEST.ilogb());
-    assert_eq!(-1074, (-Double::SMALLEST).ilogb());
-    assert_eq!(-1023, "0x1.ffffffffffffep-1024".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.ffffffffffffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-51, "0x1p-51".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.c60f120d9f87cp-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-2, "0x0.ffffp-1".parse::<Double>().unwrap().ilogb());
-    assert_eq!(-1023, "0x1.fffep-1023".parse::<Double>().unwrap().ilogb());
-    assert_eq!(1023, Double::largest().ilogb());
-    assert_eq!(1023, (-Double::largest()).ilogb());
-
-    assert_eq!(0, "0x1p+0".parse::<Single>().unwrap().ilogb());
-    assert_eq!(0, "-0x1p+0".parse::<Single>().unwrap().ilogb());
-    assert_eq!(42, "0x1p+42".parse::<Single>().unwrap().ilogb());
-    assert_eq!(-42, "0x1p-42".parse::<Single>().unwrap().ilogb());
-
-    assert_eq!(IEK_INF, Single::INFINITY.ilogb());
-    assert_eq!(IEK_INF, (-Single::INFINITY).ilogb());
-    assert_eq!(IEK_ZERO, Single::ZERO.ilogb());
-    assert_eq!(IEK_ZERO, (-Single::ZERO).ilogb());
-    assert_eq!(IEK_NAN, Single::NAN.ilogb());
-    assert_eq!(IEK_NAN, Single::snan(None).ilogb());
-
-    assert_eq!(127, Single::largest().ilogb());
-    assert_eq!(127, (-Single::largest()).ilogb());
-
-    assert_eq!(-149, Single::SMALLEST.ilogb());
-    assert_eq!(-149, (-Single::SMALLEST).ilogb());
-    assert_eq!(-126, Single::smallest_normalized().ilogb());
-    assert_eq!(-126, (-Single::smallest_normalized()).ilogb());
-}
-
-#[test]
-fn scalbn() {
-    assert!(
-        "0x1p+0"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(0),)
-    );
-    assert!(
-        "0x1p+42"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(42),)
-    );
-    assert!(
-        "0x1p-42"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(-42),)
-    );
-
-    let p_inf = Single::INFINITY;
-    let m_inf = -Single::INFINITY;
-    let p_zero = Single::ZERO;
-    let m_zero = -Single::ZERO;
-    let p_qnan = Single::NAN;
-    let m_qnan = -Single::NAN;
-    let snan = Single::snan(None);
-
-    assert!(p_inf.bitwise_eq(p_inf.scalbn(0)));
-    assert!(m_inf.bitwise_eq(m_inf.scalbn(0)));
-    assert!(p_zero.bitwise_eq(p_zero.scalbn(0)));
-    assert!(m_zero.bitwise_eq(m_zero.scalbn(0)));
-    assert!(p_qnan.bitwise_eq(p_qnan.scalbn(0)));
-    assert!(m_qnan.bitwise_eq(m_qnan.scalbn(0)));
-    assert!(!snan.scalbn(0).is_signaling());
-
-    let scalbn_snan = snan.scalbn(1);
-    assert!(scalbn_snan.is_nan() && !scalbn_snan.is_signaling());
-
-    // Make sure highest bit of payload is preserved.
-    let payload = (1 << 50) | (1 << 49) | (1234 << 32) | 1;
-
-    let snan_with_payload = Double::snan(Some(payload));
-    let quiet_payload = snan_with_payload.scalbn(1);
-    assert!(quiet_payload.is_nan() && !quiet_payload.is_signaling());
-    assert_eq!(payload, quiet_payload.to_bits() & ((1 << 51) - 1));
-
-    assert!(p_inf.bitwise_eq("0x1p+0".parse::<Single>().unwrap().scalbn(128),));
-    assert!(m_inf.bitwise_eq("-0x1p+0".parse::<Single>().unwrap().scalbn(128),));
-    assert!(p_inf.bitwise_eq("0x1p+127".parse::<Single>().unwrap().scalbn(1),));
-    assert!(p_zero.bitwise_eq("0x1p-127".parse::<Single>().unwrap().scalbn(-127),));
-    assert!(m_zero.bitwise_eq("-0x1p-127".parse::<Single>().unwrap().scalbn(-127),));
-    assert!(
-        "-0x1p-149"
-            .parse::<Single>()
-            .unwrap()
-            .bitwise_eq("-0x1p-127".parse::<Single>().unwrap().scalbn(-22),)
-    );
-    assert!(p_zero.bitwise_eq("0x1p-126".parse::<Single>().unwrap().scalbn(-24),));
-
-    let smallest_f64 = Double::SMALLEST;
-    let neg_smallest_f64 = -Double::SMALLEST;
-
-    let largest_f64 = Double::largest();
-    let neg_largest_f64 = -Double::largest();
-
-    let largest_denormal_f64 = "0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-    let neg_largest_denormal_f64 = "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-
-    assert!(smallest_f64.bitwise_eq("0x1p-1074".parse::<Double>().unwrap().scalbn(0),));
-    assert!(neg_smallest_f64.bitwise_eq("-0x1p-1074".parse::<Double>().unwrap().scalbn(0),));
-
-    assert!("0x1p+1023".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2097,),));
-
-    assert!(smallest_f64.scalbn(-2097).is_pos_zero());
-    assert!(smallest_f64.scalbn(-2098).is_pos_zero());
-    assert!(smallest_f64.scalbn(-2099).is_pos_zero());
-    assert!("0x1p+1022".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2096,),));
-    assert!("0x1p+1023".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2097,),));
-    assert!(smallest_f64.scalbn(2098).is_infinite());
-    assert!(smallest_f64.scalbn(2099).is_infinite());
-
-    // Test for integer overflows when adding to exponent.
-    assert!(smallest_f64.scalbn(-ExpInt::MAX).is_pos_zero());
-    assert!(largest_f64.scalbn(ExpInt::MAX).is_infinite());
-
-    assert!(largest_denormal_f64.bitwise_eq(largest_denormal_f64.scalbn(0),));
-    assert!(neg_largest_denormal_f64.bitwise_eq(neg_largest_denormal_f64.scalbn(0),));
-
-    assert!(
-        "0x1.ffffffffffffep-1022"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1))
-    );
-    assert!(
-        "-0x1.ffffffffffffep-1021"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(neg_largest_denormal_f64.scalbn(2))
-    );
-
-    assert!(
-        "0x1.ffffffffffffep+1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1024))
-    );
-    assert!(largest_denormal_f64.scalbn(-1023).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(-1024).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(-2048).is_pos_zero());
-    assert!(largest_denormal_f64.scalbn(2047).is_infinite());
-    assert!(largest_denormal_f64.scalbn(2098).is_infinite());
-    assert!(largest_denormal_f64.scalbn(2099).is_infinite());
-
-    assert!(
-        "0x1.ffffffffffffep-2"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1021))
-    );
-    assert!(
-        "0x1.ffffffffffffep-1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1022))
-    );
-    assert!(
-        "0x1.ffffffffffffep+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(1023))
-    );
-    assert!(
-        "0x1.ffffffffffffep+1023"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(largest_denormal_f64.scalbn(2046))
-    );
-    assert!("0x1p+974".parse::<Double>().unwrap().bitwise_eq(smallest_f64.scalbn(2048,),));
-
-    let random_denormal_f64 = "0x1.c60f120d9f87cp+51".parse::<Double>().unwrap();
-    assert!(
-        "0x1.c60f120d9f87cp-972"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-1023))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp-1"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-52))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp-2"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-53))
-    );
-    assert!(
-        "0x1.c60f120d9f87cp+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq(random_denormal_f64.scalbn(-51))
-    );
-
-    assert!(random_denormal_f64.scalbn(-2097).is_pos_zero());
-    assert!(random_denormal_f64.scalbn(-2090).is_pos_zero());
-
-    assert!("-0x1p-1073".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2097),));
-
-    assert!("-0x1p-1024".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2048),));
-
-    assert!("0x1p-1073".parse::<Double>().unwrap().bitwise_eq(largest_f64.scalbn(-2097,),));
-
-    assert!("0x1p-1074".parse::<Double>().unwrap().bitwise_eq(largest_f64.scalbn(-2098,),));
-    assert!("-0x1p-1074".parse::<Double>().unwrap().bitwise_eq(neg_largest_f64.scalbn(-2098),));
-    assert!(neg_largest_f64.scalbn(-2099).is_neg_zero());
-    assert!(largest_f64.scalbn(1).is_infinite());
-
-    assert!(
-        "0x1p+0"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq("0x1p+52".parse::<Double>().unwrap().scalbn(-52),)
-    );
-
-    assert!(
-        "0x1p-103"
-            .parse::<Double>()
-            .unwrap()
-            .bitwise_eq("0x1p-51".parse::<Double>().unwrap().scalbn(-52),)
-    );
-}
-
-#[test]
-fn frexp() {
-    let p_zero = Double::ZERO;
-    let m_zero = -Double::ZERO;
-    let one = Double::from_f64(1.0);
-    let m_one = Double::from_f64(-1.0);
-
-    let largest_denormal = "0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-    let neg_largest_denormal = "-0x1.ffffffffffffep-1023".parse::<Double>().unwrap();
-
-    let smallest = Double::SMALLEST;
-    let neg_smallest = -Double::SMALLEST;
-
-    let largest = Double::largest();
-    let neg_largest = -Double::largest();
-
-    let p_inf = Double::INFINITY;
-    let m_inf = -Double::INFINITY;
-
-    let p_qnan = Double::NAN;
-    let m_qnan = -Double::NAN;
-    let snan = Double::snan(None);
-
-    // Make sure highest bit of payload is preserved.
-    let payload = (1 << 50) | (1 << 49) | (1234 << 32) | 1;
-
-    let snan_with_payload = Double::snan(Some(payload));
-
-    let mut exp = 0;
-
-    let frac = p_zero.frexp(&mut exp);
-    assert_eq!(0, exp);
-    assert!(frac.is_pos_zero());
-
-    let frac = m_zero.frexp(&mut exp);
-    assert_eq!(0, exp);
-    assert!(frac.is_neg_zero());
-
-    let frac = one.frexp(&mut exp);
-    assert_eq!(1, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = m_one.frexp(&mut exp);
-    assert_eq!(1, exp);
-    assert!("-0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = largest_denormal.frexp(&mut exp);
-    assert_eq!(-1022, exp);
-    assert!("0x1.ffffffffffffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_largest_denormal.frexp(&mut exp);
-    assert_eq!(-1022, exp);
-    assert!("-0x1.ffffffffffffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = smallest.frexp(&mut exp);
-    assert_eq!(-1073, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_smallest.frexp(&mut exp);
-    assert_eq!(-1073, exp);
-    assert!("-0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = largest.frexp(&mut exp);
-    assert_eq!(1024, exp);
-    assert!("0x1.fffffffffffffp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = neg_largest.frexp(&mut exp);
-    assert_eq!(1024, exp);
-    assert!("-0x1.fffffffffffffp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = p_inf.frexp(&mut exp);
-    assert_eq!(IEK_INF, exp);
-    assert!(frac.is_infinite() && !frac.is_negative());
-
-    let frac = m_inf.frexp(&mut exp);
-    assert_eq!(IEK_INF, exp);
-    assert!(frac.is_infinite() && frac.is_negative());
-
-    let frac = p_qnan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan());
-
-    let frac = m_qnan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan());
-
-    let frac = snan.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan() && !frac.is_signaling());
-
-    let frac = snan_with_payload.frexp(&mut exp);
-    assert_eq!(IEK_NAN, exp);
-    assert!(frac.is_nan() && !frac.is_signaling());
-    assert_eq!(payload, frac.to_bits() & ((1 << 51) - 1));
-
-    let frac = "0x0.ffffp-1".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(-1, exp);
-    assert!("0x1.fffep-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = "0x1p-51".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(-50, exp);
-    assert!("0x1p-1".parse::<Double>().unwrap().bitwise_eq(frac));
-
-    let frac = "0x1.c60f120d9f87cp+51".parse::<Double>().unwrap().frexp(&mut exp);
-    assert_eq!(52, exp);
-    assert!("0x1.c60f120d9f87cp-1".parse::<Double>().unwrap().bitwise_eq(frac));
-}
-
-#[test]
-fn modulo() {
-    let mut status;
-    {
-        let f1 = "1.5".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.5".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0.5".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.5".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1.3333333333333p-2".parse::<Double>().unwrap(); // 0.3
-        let f2 = "0x1.47ae147ae147bp-7".parse::<Double>().unwrap(); // 0.01
-        // 0.009999999999999983
-        let expected = "0x1.47ae147ae1471p-7".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1p64".parse::<Double>().unwrap(); // 1.8446744073709552e19
-        let f2 = "1.5".parse::<Double>().unwrap();
-        let expected = "1.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0x1p1000".parse::<Double>().unwrap();
-        let f2 = "0x1p-1000".parse::<Double>().unwrap();
-        let expected = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "0.0".parse::<Double>().unwrap();
-        let f2 = "1.0".parse::<Double>().unwrap();
-        let expected = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).bitwise_eq(expected));
-        assert_eq!(status, Status::OK);
-    }
-    {
-        let f1 = "1.0".parse::<Double>().unwrap();
-        let f2 = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-    {
-        let f1 = "0.0".parse::<Double>().unwrap();
-        let f2 = "0.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-    {
-        let f1 = Double::INFINITY;
-        let f2 = "1.0".parse::<Double>().unwrap();
-        assert!(unpack!(status=, f1 % f2).is_nan());
-        assert_eq!(status, Status::INVALID_OP);
-    }
-}
diff --git a/compiler/rustc_apfloat/tests/ppc.rs b/compiler/rustc_apfloat/tests/ppc.rs
deleted file mode 100644
index c769d26..0000000
--- a/compiler/rustc_apfloat/tests/ppc.rs
+++ /dev/null
@@ -1,530 +0,0 @@
-use rustc_apfloat::ppc::DoubleDouble;
-use rustc_apfloat::{Category, Float, Round};
-
-use std::cmp::Ordering;
-
-#[test]
-fn ppc_double_double() {
-    let test = DoubleDouble::ZERO;
-    let expected = "0x0p+0".parse::<DoubleDouble>().unwrap();
-    assert!(test.is_zero());
-    assert!(!test.is_negative());
-    assert!(test.bitwise_eq(expected));
-    assert_eq!(0, test.to_bits());
-
-    let test = -DoubleDouble::ZERO;
-    let expected = "-0x0p+0".parse::<DoubleDouble>().unwrap();
-    assert!(test.is_zero());
-    assert!(test.is_negative());
-    assert!(test.bitwise_eq(expected));
-    assert_eq!(0x8000000000000000, test.to_bits());
-
-    let test = "1.0".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x3ff0000000000000, test.to_bits());
-
-    // LDBL_MAX
-    let test = "1.79769313486231580793728971405301e+308".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, test.to_bits());
-
-    // LDBL_MIN
-    let test = "2.00416836000897277799610805135016e-292".parse::<DoubleDouble>().unwrap();
-    assert_eq!(0x0000000000000000_0360000000000000, test.to_bits());
-}
-
-#[test]
-fn ppc_double_double_add_special() {
-    let data = [
-        // (1 + 0) + (-1 + 0) = Category::Zero
-        (0x3ff0000000000000, 0xbff0000000000000, Category::Zero, Round::NearestTiesToEven),
-        // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x7948000000000000,
-            Category::Infinity,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change the 4th 0x75effffffffffffe to 0x75efffffffffffff when
-        // DoubleDouble's fallback is gone.
-        // LDBL_MAX + (1.011111... >> (1023 - 106) + (1.1111111...0 >> (1023 -
-        // 160))) = Category::Normal
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x75effffffffffffe_7947ffffffffffff,
-            Category::Normal,
-            Round::NearestTiesToEven,
-        ),
-        // LDBL_MAX + (1.1 >> (1023 - 106) + 0)) = Category::Infinity
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Category::Infinity,
-            Round::NearestTiesToEven,
-        ),
-        // NaN + (1 + 0) = Category::NaN
-        (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.add_r(a2, round).value;
-
-            assert_eq!(expected, a1.category(), "{:#x} + {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.add_r(a1, round).value;
-
-            assert_eq!(expected, a2.category(), "{:#x} + {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_add() {
-    let data = [
-        // (1 + 0) + (1e-105 + 0) = (1 + 1e-105)
-        (
-            0x3ff0000000000000,
-            0x3960000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) + (1e-106 + 0) = (1 + 1e-106)
-        (
-            0x3ff0000000000000,
-            0x3950000000000000,
-            0x3950000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 1e-106) + (1e-106 + 0) = (1 + 1e-105)
-        (
-            0x3950000000000000_3ff0000000000000,
-            0x3950000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) + (epsilon + 0) = (1 + epsilon)
-        (
-            0x3ff0000000000000,
-            0x0000000000000001,
-            0x0000000000000001_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
-        // DoubleDouble's fallback is gone.
-        // (DBL_MAX - 1 << (1023 - 105)) + (1 << (1023 - 53) + 0) = DBL_MAX +
-        // 1.11111... << (1023 - 52)
-        (
-            0xf950000000000000_7fefffffffffffff,
-            0x7c90000000000000,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-        // FIXME: change 0xf950000000000000 to 0xf940000000000000, when
-        // DoubleDouble's fallback is gone.
-        // (1 << (1023 - 53) + 0) + (DBL_MAX - 1 << (1023 - 105)) = DBL_MAX +
-        // 1.11111... << (1023 - 52)
-        (
-            0x7c90000000000000,
-            0xf950000000000000_7fefffffffffffff,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.add_r(a2, round).value;
-
-            assert_eq!(expected, a1.to_bits(), "{:#x} + {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.add_r(a1, round).value;
-
-            assert_eq!(expected, a2.to_bits(), "{:#x} + {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_subtract() {
-    let data = [
-        // (1 + 0) - (-1e-105 + 0) = (1 + 1e-105)
-        (
-            0x3ff0000000000000,
-            0xb960000000000000,
-            0x3960000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + 0) - (-1e-106 + 0) = (1 + 1e-106)
-        (
-            0x3ff0000000000000,
-            0xb950000000000000,
-            0x3950000000000000_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        let mut a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        a1 = a1.sub_r(a2, round).value;
-
-        assert_eq!(expected, a1.to_bits(), "{:#x} - {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_multiply_special() {
-    let data = [
-        // Category::NaN * Category::NaN = Category::NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Zero = Category::NaN
-        (0x7ff8000000000000, 0, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Infinity = Category::NaN
-        (0x7ff8000000000000, 0x7ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::NaN * Category::Normal = Category::NaN
-        (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Infinity = Category::Infinity
-        (0x7ff0000000000000, 0x7ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Zero = Category::NaN
-        (0x7ff0000000000000, 0, Category::NaN, Round::NearestTiesToEven),
-        // Category::Infinity * Category::Normal = Category::Infinity
-        (0x7ff0000000000000, 0x3ff0000000000000, Category::Infinity, Round::NearestTiesToEven),
-        // Category::Zero * Category::Zero = Category::Zero
-        (0, 0, Category::Zero, Round::NearestTiesToEven),
-        // Category::Zero * Category::Normal = Category::Zero
-        (0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.mul_r(a2, round).value;
-
-            assert_eq!(expected, a1.category(), "{:#x} * {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.mul_r(a1, round).value;
-
-            assert_eq!(expected, a2.category(), "{:#x} * {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_multiply() {
-    let data = [
-        // 1/3 * 3 = 1.0
-        (
-            0x3c75555555555556_3fd5555555555555,
-            0x4008000000000000,
-            0x3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + epsilon) * (1 + 0) = Category::Zero
-        (
-            0x0000000000000001_3ff0000000000000,
-            0x3ff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (1 + epsilon) * (1 + epsilon) = 1 + 2 * epsilon
-        (
-            0x0000000000000001_3ff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0x0000000000000002_3ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // -(1 + epsilon) * (1 + epsilon) = -1
-        (
-            0x0000000000000001_bff0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0xbff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (0.5 + 0) * (1 + 2 * epsilon) = 0.5 + epsilon
-        (
-            0x3fe0000000000000,
-            0x0000000000000002_3ff0000000000000,
-            0x0000000000000001_3fe0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // (0.5 + 0) * (1 + epsilon) = 0.5
-        (
-            0x3fe0000000000000,
-            0x0000000000000001_3ff0000000000000,
-            0x3fe0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 106) = inf
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3950000000000000_3ff0000000000000,
-            0x7ff0000000000000,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 107) > __LDBL_MAX__, but not inf, yes =_=|||
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3940000000000000_3ff0000000000000,
-            0x7c8fffffffffffff_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-        // __LDBL_MAX__ * (1 + 1 << 108) = __LDBL_MAX__
-        (
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            0x3930000000000000_3ff0000000000000,
-            0x7c8ffffffffffffe_7fefffffffffffff,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        {
-            let mut a1 = DoubleDouble::from_bits(op1);
-            let a2 = DoubleDouble::from_bits(op2);
-            a1 = a1.mul_r(a2, round).value;
-
-            assert_eq!(expected, a1.to_bits(), "{:#x} * {:#x}", op1, op2);
-        }
-        {
-            let a1 = DoubleDouble::from_bits(op1);
-            let mut a2 = DoubleDouble::from_bits(op2);
-            a2 = a2.mul_r(a1, round).value;
-
-            assert_eq!(expected, a2.to_bits(), "{:#x} * {:#x}", op2, op1);
-        }
-    }
-}
-
-#[test]
-fn ppc_double_double_divide() {
-    // FIXME: Only a sanity check for now. Add more edge cases when the
-    // double-double algorithm is implemented.
-    let data = [
-        // 1 / 3 = 1/3
-        (
-            0x3ff0000000000000,
-            0x4008000000000000,
-            0x3c75555555555556_3fd5555555555555,
-            Round::NearestTiesToEven,
-        ),
-    ];
-
-    for (op1, op2, expected, round) in data {
-        let mut a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        a1 = a1.div_r(a2, round).value;
-
-        assert_eq!(expected, a1.to_bits(), "{:#x} / {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_remainder() {
-    let data = [
-        // ieee_rem(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3ca4000000000000_3ff4000000000000,
-            0x3c90000000000000_3fe0000000000000,
-        ),
-        // ieee_rem(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (-0.5 - 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3cac000000000000_3ffc000000000000,
-            0xbc90000000000000_bfe0000000000000,
-        ),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        let result = a1.ieee_rem(a2).value;
-
-        assert_eq!(expected, result.to_bits(), "ieee_rem({:#x}, {:#x})", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_mod() {
-    let data = [
-        // mod(3.0 + 3.0 << 53, 1.25 + 1.25 << 53) = (0.5 + 0.5 << 53)
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3ca4000000000000_3ff4000000000000,
-            0x3c90000000000000_3fe0000000000000,
-        ),
-        // mod(3.0 + 3.0 << 53, 1.75 + 1.75 << 53) = (1.25 + 1.25 << 53)
-        // 0xbc98000000000000 doesn't seem right, but it's what we currently have.
-        // FIXME: investigate
-        (
-            0x3cb8000000000000_4008000000000000,
-            0x3cac000000000000_3ffc000000000000,
-            0xbc98000000000000_3ff4000000000001,
-        ),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        let r = (a1 % a2).value;
-
-        assert_eq!(expected, r.to_bits(), "fmod({:#x}, {:#x})", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_fma() {
-    // Sanity check for now.
-    let mut a = "2".parse::<DoubleDouble>().unwrap();
-    a = a.mul_add("3".parse::<DoubleDouble>().unwrap(), "4".parse::<DoubleDouble>().unwrap()).value;
-    assert_eq!(Some(Ordering::Equal), "10".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-}
-
-#[test]
-fn ppc_double_double_round_to_integral() {
-    {
-        let a = "1.5".parse::<DoubleDouble>().unwrap();
-        let a = a.round_to_integral(Round::NearestTiesToEven).value;
-        assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-    }
-    {
-        let a = "2.5".parse::<DoubleDouble>().unwrap();
-        let a = a.round_to_integral(Round::NearestTiesToEven).value;
-        assert_eq!(Some(Ordering::Equal), "2".parse::<DoubleDouble>().unwrap().partial_cmp(&a));
-    }
-}
-
-#[test]
-fn ppc_double_double_compare() {
-    let data = [
-        // (1 + 0) = (1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000000, Some(Ordering::Equal)),
-        // (1 + 0) < (1.00...1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000001, Some(Ordering::Less)),
-        // (1.00...1 + 0) > (1 + 0)
-        (0x3ff0000000000001, 0x3ff0000000000000, Some(Ordering::Greater)),
-        // (1 + 0) < (1 + epsilon)
-        (0x3ff0000000000000, 0x0000000000000001_3ff0000000000001, Some(Ordering::Less)),
-        // NaN != NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, None),
-        // (1 + 0) != NaN
-        (0x3ff0000000000000, 0x7ff8000000000000, None),
-        // Inf = Inf
-        (0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
-    }
-}
-
-#[test]
-fn ppc_double_double_bitwise_eq() {
-    let data = [
-        // (1 + 0) = (1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000000, true),
-        // (1 + 0) != (1.00...1 + 0)
-        (0x3ff0000000000000, 0x3ff0000000000001, false),
-        // NaN = NaN
-        (0x7ff8000000000000, 0x7ff8000000000000, true),
-        // NaN != NaN with a different bit pattern
-        (0x7ff8000000000000, 0x3ff0000000000000_7ff8000000000000, false),
-        // Inf = Inf
-        (0x7ff0000000000000, 0x7ff0000000000000, true),
-    ];
-
-    for (op1, op2, expected) in data {
-        let a1 = DoubleDouble::from_bits(op1);
-        let a2 = DoubleDouble::from_bits(op2);
-        assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
-    }
-}
-
-#[test]
-fn ppc_double_double_change_sign() {
-    let float = DoubleDouble::from_bits(0xbcb0000000000000_400f000000000000);
-    {
-        let actual = float.copy_sign("1".parse::<DoubleDouble>().unwrap());
-        assert_eq!(0xbcb0000000000000_400f000000000000, actual.to_bits());
-    }
-    {
-        let actual = float.copy_sign("-1".parse::<DoubleDouble>().unwrap());
-        assert_eq!(0x3cb0000000000000_c00f000000000000, actual.to_bits());
-    }
-}
-
-#[test]
-fn ppc_double_double_factories() {
-    assert_eq!(0, DoubleDouble::ZERO.to_bits());
-    assert_eq!(0x7c8ffffffffffffe_7fefffffffffffff, DoubleDouble::largest().to_bits());
-    assert_eq!(0x0000000000000001, DoubleDouble::SMALLEST.to_bits());
-    assert_eq!(0x0360000000000000, DoubleDouble::smallest_normalized().to_bits());
-    assert_eq!(0x0000000000000000_8000000000000000, (-DoubleDouble::ZERO).to_bits());
-    assert_eq!(0xfc8ffffffffffffe_ffefffffffffffff, (-DoubleDouble::largest()).to_bits());
-    assert_eq!(0x0000000000000000_8000000000000001, (-DoubleDouble::SMALLEST).to_bits());
-    assert_eq!(
-        0x0000000000000000_8360000000000000,
-        (-DoubleDouble::smallest_normalized()).to_bits()
-    );
-    assert!(DoubleDouble::SMALLEST.is_smallest());
-    assert!(DoubleDouble::largest().is_largest());
-}
-
-#[test]
-fn ppc_double_double_is_denormal() {
-    assert!(DoubleDouble::SMALLEST.is_denormal());
-    assert!(!DoubleDouble::largest().is_denormal());
-    assert!(!DoubleDouble::smallest_normalized().is_denormal());
-    {
-        // (4 + 3) is not normalized
-        let data = 0x4008000000000000_4010000000000000;
-        assert!(DoubleDouble::from_bits(data).is_denormal());
-    }
-}
-
-#[test]
-fn ppc_double_double_exact_inverse() {
-    assert!(
-        "2.0"
-            .parse::<DoubleDouble>()
-            .unwrap()
-            .get_exact_inverse()
-            .unwrap()
-            .bitwise_eq("0.5".parse::<DoubleDouble>().unwrap())
-    );
-}
-
-#[test]
-fn ppc_double_double_scalbn() {
-    // 3.0 + 3.0 << 53
-    let input = 0x3cb8000000000000_4008000000000000;
-    let result = DoubleDouble::from_bits(input).scalbn(1);
-    // 6.0 + 6.0 << 53
-    assert_eq!(0x3cc8000000000000_4018000000000000, result.to_bits());
-}
-
-#[test]
-fn ppc_double_double_frexp() {
-    // 3.0 + 3.0 << 53
-    let input = 0x3cb8000000000000_4008000000000000;
-    let mut exp = 0;
-    // 0.75 + 0.75 << 53
-    let result = DoubleDouble::from_bits(input).frexp(&mut exp);
-    assert_eq!(2, exp);
-    assert_eq!(0x3c98000000000000_3fe8000000000000, result.to_bits());
-}
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index ba47ebd..e45b7c1 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -11,6 +11,7 @@
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(no_crate_inject, attr(deny(warnings)))
 )]
+#![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(new_uninit)]
 #![feature(maybe_uninit_slice)]
@@ -23,17 +24,18 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
 #![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
 
 use smallvec::SmallVec;
 
 use std::alloc::Layout;
 use std::cell::{Cell, RefCell};
-use std::cmp;
 use std::marker::PhantomData;
 use std::mem::{self, MaybeUninit};
 use std::ptr::{self, NonNull};
 use std::slice;
+use std::{cmp, intrinsics};
 
 #[inline(never)]
 #[cold]
@@ -362,6 +364,22 @@
 
 unsafe impl<T: Send> Send for TypedArena<T> {}
 
+#[inline(always)]
+fn align_down(val: usize, align: usize) -> usize {
+    debug_assert!(align.is_power_of_two());
+    val & !(align - 1)
+}
+
+#[inline(always)]
+fn align_up(val: usize, align: usize) -> usize {
+    debug_assert!(align.is_power_of_two());
+    (val + align - 1) & !(align - 1)
+}
+
+// Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them
+// to optimize away alignment code.
+const DROPLESS_ALIGNMENT: usize = mem::align_of::<usize>();
+
 /// An arena that can hold objects of multiple different types that impl `Copy`
 /// and/or satisfy `!mem::needs_drop`.
 pub struct DroplessArena {
@@ -374,6 +392,8 @@
     /// start. (This is slightly simpler and faster than allocating upwards,
     /// see <https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html>.)
     /// When this pointer crosses the start pointer, a new chunk is allocated.
+    ///
+    /// This is kept aligned to DROPLESS_ALIGNMENT.
     end: Cell<*mut u8>,
 
     /// A vector of arena chunks.
@@ -394,9 +414,11 @@
 }
 
 impl DroplessArena {
-    #[inline(never)]
-    #[cold]
-    fn grow(&self, additional: usize) {
+    fn grow(&self, layout: Layout) {
+        // Add some padding so we can align `self.end` while
+        // stilling fitting in a `layout` allocation.
+        let additional = layout.size() + cmp::max(DROPLESS_ALIGNMENT, layout.align()) - 1;
+
         unsafe {
             let mut chunks = self.chunks.borrow_mut();
             let mut new_cap;
@@ -415,13 +437,35 @@
             // Also ensure that this chunk can fit `additional`.
             new_cap = cmp::max(additional, new_cap);
 
-            let mut chunk = ArenaChunk::new(new_cap);
+            let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE));
             self.start.set(chunk.start());
-            self.end.set(chunk.end());
+
+            // Align the end to DROPLESS_ALIGNMENT
+            let end = align_down(chunk.end().addr(), DROPLESS_ALIGNMENT);
+
+            // Make sure we don't go past `start`. This should not happen since the allocation
+            // should be at least DROPLESS_ALIGNMENT - 1 bytes.
+            debug_assert!(chunk.start().addr() <= end);
+
+            self.end.set(chunk.end().with_addr(end));
+
             chunks.push(chunk);
         }
     }
 
+    #[inline(never)]
+    #[cold]
+    fn grow_and_alloc_raw(&self, layout: Layout) -> *mut u8 {
+        self.grow(layout);
+        self.alloc_raw_without_grow(layout).unwrap()
+    }
+
+    #[inline(never)]
+    #[cold]
+    fn grow_and_alloc<T>(&self) -> *mut u8 {
+        self.grow_and_alloc_raw(Layout::new::<T>())
+    }
+
     /// Allocates a byte slice with specified layout from the current memory
     /// chunk. Returns `None` if there is no free space left to satisfy the
     /// request.
@@ -431,12 +475,17 @@
         let old_end = self.end.get();
         let end = old_end.addr();
 
-        let align = layout.align();
-        let bytes = layout.size();
+        // Align allocated bytes so that `self.end` stays aligned to DROPLESS_ALIGNMENT
+        let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
 
-        let new_end = end.checked_sub(bytes)? & !(align - 1);
+        // Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT
+        unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) };
+
+        let new_end = align_down(end.checked_sub(bytes)?, layout.align());
         if start <= new_end {
             let new_end = old_end.with_addr(new_end);
+            // `new_end` is aligned to DROPLESS_ALIGNMENT as `align_down` preserves alignment
+            // as both `end` and `bytes` are already aligned to DROPLESS_ALIGNMENT.
             self.end.set(new_end);
             Some(new_end)
         } else {
@@ -447,21 +496,26 @@
     #[inline]
     pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
         assert!(layout.size() != 0);
-        loop {
-            if let Some(a) = self.alloc_raw_without_grow(layout) {
-                break a;
-            }
-            // No free space left. Allocate a new chunk to satisfy the request.
-            // On failure the grow will panic or abort.
-            self.grow(layout.size());
+        if let Some(a) = self.alloc_raw_without_grow(layout) {
+            return a;
         }
+        // No free space left. Allocate a new chunk to satisfy the request.
+        // On failure the grow will panic or abort.
+        self.grow_and_alloc_raw(layout)
     }
 
     #[inline]
     pub fn alloc<T>(&self, object: T) -> &mut T {
         assert!(!mem::needs_drop::<T>());
+        assert!(mem::size_of::<T>() != 0);
 
-        let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T;
+        let mem = if let Some(a) = self.alloc_raw_without_grow(Layout::for_value::<T>(&object)) {
+            a
+        } else {
+            // No free space left. Allocate a new chunk to satisfy the request.
+            // On failure the grow will panic or abort.
+            self.grow_and_alloc::<T>()
+        } as *mut T;
 
         unsafe {
             // Write into uninitialized memory.
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index a7198fb..58725a0 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -14,7 +14,7 @@
 //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters.
 //! - [`EnumDef`] and [`Variant`]: Enum declaration.
 //! - [`MetaItemLit`] and [`LitKind`]: Literal expressions.
-//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation.
+//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`]: Macro definition and invocation.
 //! - [`Attribute`]: Metadata associated with item.
 //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
 
@@ -313,6 +313,16 @@
     MaybeConstMaybe,
 }
 
+impl TraitBoundModifier {
+    pub fn to_constness(self) -> Const {
+        match self {
+            // FIXME(effects) span
+            Self::MaybeConst => Const::Yes(DUMMY_SP),
+            _ => Const::No,
+        }
+    }
+}
+
 /// The AST represents all type param bounds as types.
 /// `typeck::collect::compute_bounds` matches these against
 /// the "special" built-in traits (see `middle::lang_items`) and
@@ -1462,7 +1472,8 @@
     /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
     Field(P<Expr>, Ident),
     /// An indexing operation (e.g., `foo[2]`).
-    Index(P<Expr>, P<Expr>),
+    /// The span represents the span of the `[2]`, including brackets.
+    Index(P<Expr>, P<Expr>, Span),
     /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assignment).
     Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
     /// An underscore, used in destructuring assignment to ignore a value.
@@ -1693,7 +1704,7 @@
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct DelimArgs {
     pub dspan: DelimSpan,
-    pub delim: MacDelimiter,
+    pub delim: Delimiter, // Note: `Delimiter::Invisible` never occurs
     pub tokens: TokenStream,
 }
 
@@ -1701,7 +1712,7 @@
     /// Whether a macro with these arguments needs a semicolon
     /// when used as a standalone item or statement.
     pub fn need_semicolon(&self) -> bool {
-        !matches!(self, DelimArgs { delim: MacDelimiter::Brace, .. })
+        !matches!(self, DelimArgs { delim: Delimiter::Brace, .. })
     }
 }
 
@@ -1717,32 +1728,6 @@
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
-pub enum MacDelimiter {
-    Parenthesis,
-    Bracket,
-    Brace,
-}
-
-impl MacDelimiter {
-    pub fn to_token(self) -> Delimiter {
-        match self {
-            MacDelimiter::Parenthesis => Delimiter::Parenthesis,
-            MacDelimiter::Bracket => Delimiter::Bracket,
-            MacDelimiter::Brace => Delimiter::Brace,
-        }
-    }
-
-    pub fn from_token(delim: Delimiter) -> Option<MacDelimiter> {
-        match delim {
-            Delimiter::Parenthesis => Some(MacDelimiter::Parenthesis),
-            Delimiter::Bracket => Some(MacDelimiter::Bracket),
-            Delimiter::Brace => Some(MacDelimiter::Brace),
-            Delimiter::Invisible => None,
-        }
-    }
-}
-
 /// Represents a macro definition.
 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct MacroDef {
@@ -2353,7 +2338,12 @@
     /// Builds a `Param` object from `ExplicitSelf`.
     pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
         let span = eself.span.to(eself_ident.span);
-        let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None });
+        let infer_ty = P(Ty {
+            id: DUMMY_NODE_ID,
+            kind: TyKind::ImplicitSelf,
+            span: eself_ident.span,
+            tokens: None,
+        });
         let (mutbl, ty) = match eself.node {
             SelfKind::Explicit(ty, mutbl) => (mutbl, ty),
             SelfKind::Value(mutbl) => (mutbl, infer_ty),
@@ -2942,6 +2932,7 @@
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct ConstItem {
     pub defaultness: Defaultness,
+    pub generics: Generics,
     pub ty: P<Ty>,
     pub expr: Option<P<Expr>>,
 }
@@ -3053,6 +3044,7 @@
         match self {
             Self::Fn(box Fn { generics, .. })
             | Self::TyAlias(box TyAlias { generics, .. })
+            | Self::Const(box ConstItem { generics, .. })
             | Self::Enum(_, generics)
             | Self::Struct(_, generics)
             | Self::Union(_, generics)
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 15fe295..19a2b30 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -2,7 +2,7 @@
 
 use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
 use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
-use crate::ast::{MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
+use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
 use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
@@ -196,7 +196,7 @@
 
     fn meta_item_list(&self) -> Option<ThinVec<NestedMetaItem>> {
         match &self.args {
-            AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
+            AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
                 MetaItemKind::list_from_tokens(args.tokens.clone())
             }
             AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
@@ -285,17 +285,17 @@
         self.kind.value_str()
     }
 
-    fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
+    fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
     where
-        I: Iterator<Item = TokenTree>,
+        I: Iterator<Item = &'a TokenTree>,
     {
         // FIXME: Share code with `parse_path`.
-        let path = match tokens.next().map(TokenTree::uninterpolate) {
-            Some(TokenTree::Token(
-                Token { kind: kind @ (token::Ident(..) | token::ModSep), span },
+        let path = match tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref() {
+            Some(&TokenTree::Token(
+                Token { kind: ref kind @ (token::Ident(..) | token::ModSep), span },
                 _,
             )) => 'arm: {
-                let mut segments = if let token::Ident(name, _) = kind {
+                let mut segments = if let &token::Ident(name, _) = kind {
                     if let Some(TokenTree::Token(Token { kind: token::ModSep, .. }, _)) =
                         tokens.peek()
                     {
@@ -308,8 +308,8 @@
                     thin_vec![PathSegment::path_root(span)]
                 };
                 loop {
-                    if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
-                        tokens.next().map(TokenTree::uninterpolate)
+                    if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
+                        tokens.next().map(|tt| TokenTree::uninterpolate(tt)).as_deref()
                     {
                         segments.push(PathSegment::from_ident(Ident::new(name, span)));
                     } else {
@@ -326,7 +326,7 @@
                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
                 Path { span, segments, tokens: None }
             }
-            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &*nt {
+            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
                 token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
                 token::Nonterminal::NtPath(path) => (**path).clone(),
                 _ => return None,
@@ -354,7 +354,7 @@
     }
 
     fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<NestedMetaItem>> {
-        let mut tokens = tokens.into_trees().peekable();
+        let mut tokens = tokens.trees().peekable();
         let mut result = ThinVec::new();
         while tokens.peek().is_some() {
             let item = NestedMetaItem::from_tokens(&mut tokens)?;
@@ -367,12 +367,12 @@
         Some(result)
     }
 
-    fn name_value_from_tokens(
-        tokens: &mut impl Iterator<Item = TokenTree>,
+    fn name_value_from_tokens<'a>(
+        tokens: &mut impl Iterator<Item = &'a TokenTree>,
     ) -> Option<MetaItemKind> {
         match tokens.next() {
             Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => {
-                MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees())
+                MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
             }
             Some(TokenTree::Token(token, _)) => {
                 MetaItemLit::from_token(&token).map(MetaItemKind::NameValue)
@@ -381,8 +381,8 @@
         }
     }
 
-    fn from_tokens(
-        tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
+    fn from_tokens<'a>(
+        tokens: &mut iter::Peekable<impl Iterator<Item = &'a TokenTree>>,
     ) -> Option<MetaItemKind> {
         match tokens.peek() {
             Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
@@ -402,11 +402,9 @@
     fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
         match args {
             AttrArgs::Empty => Some(MetaItemKind::Word),
-            AttrArgs::Delimited(DelimArgs {
-                dspan: _,
-                delim: MacDelimiter::Parenthesis,
-                tokens,
-            }) => MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List),
+            AttrArgs::Delimited(DelimArgs { dspan: _, delim: Delimiter::Parenthesis, tokens }) => {
+                MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
+            }
             AttrArgs::Delimited(..) => None,
             AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => match expr.kind {
                 ExprKind::Lit(token_lit) => {
@@ -501,9 +499,9 @@
         self.meta_item().is_some()
     }
 
-    fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
+    fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
     where
-        I: Iterator<Item = TokenTree>,
+        I: Iterator<Item = &'a TokenTree>,
     {
         match tokens.peek() {
             Some(TokenTree::Token(token, _))
@@ -513,9 +511,8 @@
                 return Some(NestedMetaItem::Lit(lit));
             }
             Some(TokenTree::Delimited(_, Delimiter::Invisible, inner_tokens)) => {
-                let inner_tokens = inner_tokens.clone();
                 tokens.next();
-                return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
+                return NestedMetaItem::from_tokens(&mut inner_tokens.trees().peekable());
             }
             _ => {}
         }
@@ -579,7 +576,7 @@
     let path = Path::from_ident(outer_ident);
     let attr_args = AttrArgs::Delimited(DelimArgs {
         dspan: DelimSpan::from_single(span),
-        delim: MacDelimiter::Parenthesis,
+        delim: Delimiter::Parenthesis,
         tokens: inner_tokens,
     });
     mk_attr(g, style, path, attr_args, span)
diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs
index e87f6e8..f825b10 100644
--- a/compiler/rustc_ast/src/expand/allocator.rs
+++ b/compiler/rustc_ast/src/expand/allocator.rs
@@ -33,29 +33,41 @@
 
 pub struct AllocatorMethod {
     pub name: Symbol,
-    pub inputs: &'static [AllocatorTy],
+    pub inputs: &'static [AllocatorMethodInput],
     pub output: AllocatorTy,
 }
 
+pub struct AllocatorMethodInput {
+    pub name: &'static str,
+    pub ty: AllocatorTy,
+}
+
 pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
     AllocatorMethod {
         name: sym::alloc,
-        inputs: &[AllocatorTy::Layout],
+        inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
         name: sym::dealloc,
-        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
+        inputs: &[
+            AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr },
+            AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout },
+        ],
         output: AllocatorTy::Unit,
     },
     AllocatorMethod {
         name: sym::realloc,
-        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
+        inputs: &[
+            AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr },
+            AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout },
+            AllocatorMethodInput { name: "new_size", ty: AllocatorTy::Usize },
+        ],
         output: AllocatorTy::ResultPtr,
     },
     AllocatorMethod {
         name: sym::alloc_zeroed,
-        inputs: &[AllocatorTy::Layout],
+        inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }],
         output: AllocatorTy::ResultPtr,
     },
 ];
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
index 699946f..805596f 100644
--- a/compiler/rustc_ast/src/format.rs
+++ b/compiler/rustc_ast/src/format.rs
@@ -67,12 +67,6 @@
     names: FxHashMap<Symbol, usize>,
 }
 
-// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
-#[cfg(parallel_compiler)]
-unsafe impl Sync for FormatArguments {}
-#[cfg(parallel_compiler)]
-unsafe impl Send for FormatArguments {}
-
 impl FormatArguments {
     pub fn new() -> Self {
         Self {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 53a9c9a..48e9b18 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -13,6 +13,7 @@
 use crate::{ast::*, StaticItem};
 
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Ident;
@@ -1149,10 +1150,11 @@
 }
 
 fn visit_const_item<T: MutVisitor>(
-    ConstItem { defaultness, ty, expr }: &mut ConstItem,
+    ConstItem { defaultness, generics, ty, expr }: &mut ConstItem,
     visitor: &mut T,
 ) {
     visit_defaultness(defaultness, visitor);
+    visitor.visit_generics(generics);
     visitor.visit_ty(ty);
     visit_opt(expr, |expr| visitor.visit_expr(expr));
 }
@@ -1368,7 +1370,7 @@
         ExprKind::If(cond, tr, fl) => {
             vis.visit_expr(cond);
             vis.visit_block(tr);
-            visit_opt(fl, |fl| vis.visit_expr(fl));
+            visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl)));
         }
         ExprKind::While(cond, body, label) => {
             vis.visit_expr(cond);
@@ -1399,7 +1401,7 @@
             fn_decl,
             body,
             fn_decl_span,
-            fn_arg_span: _,
+            fn_arg_span,
         }) => {
             vis.visit_closure_binder(binder);
             visit_constness(constness, vis);
@@ -1407,6 +1409,7 @@
             vis.visit_fn_decl(fn_decl);
             vis.visit_expr(body);
             vis.visit_span(fn_decl_span);
+            vis.visit_span(fn_arg_span);
         }
         ExprKind::Block(blk, label) => {
             vis.visit_block(blk);
@@ -1419,9 +1422,10 @@
             vis.visit_expr(expr);
             vis.visit_span(await_kw_span);
         }
-        ExprKind::Assign(el, er, _) => {
+        ExprKind::Assign(el, er, span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
+            vis.visit_span(span);
         }
         ExprKind::AssignOp(_op, el, er) => {
             vis.visit_expr(el);
@@ -1431,9 +1435,10 @@
             vis.visit_expr(el);
             vis.visit_ident(ident);
         }
-        ExprKind::Index(el, er) => {
+        ExprKind::Index(el, er, brackets_span) => {
             vis.visit_expr(el);
             vis.visit_expr(er);
+            vis.visit_span(brackets_span);
         }
         ExprKind::Range(e1, e2, _lim) => {
             visit_opt(e1, |e1| vis.visit_expr(e1));
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 6646fa9..f4ad0ef 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -11,7 +11,7 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_macros::HashStable_Generic;
 use rustc_span::symbol::{kw, sym};
-#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
+#[allow(hidden_glob_reexports)]
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, edition::Edition, Span, DUMMY_SP};
 use std::borrow::Cow;
@@ -41,8 +41,6 @@
 /// Describes how a sequence of token trees is delimited.
 /// Cannot use `proc_macro::Delimiter` directly because this
 /// structure should implement some additional traits.
-/// The `None` variant is also renamed to `Invisible` to be
-/// less confusing and better convey the semantics.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(Encodable, Decodable, Hash, HashStable_Generic)]
 pub enum Delimiter {
@@ -226,7 +224,9 @@
             .contains(&name)
 }
 
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+// SAFETY: due to the `Clone` impl below, all fields of all variants other than
+// `Interpolated` must impl `Copy`.
+#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum TokenKind {
     /* Expression-operator symbols. */
     Eq,
@@ -299,6 +299,19 @@
     Eof,
 }
 
+impl Clone for TokenKind {
+    fn clone(&self) -> Self {
+        // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So
+        // for all other variants, this implementation of `clone` is just like
+        // a copy. This is faster than the `derive(Clone)` version which has a
+        // separate path for every variant.
+        match self {
+            Interpolated(nt) => Interpolated(nt.clone()),
+            _ => unsafe { std::ptr::read(self) },
+        }
+    }
+}
+
 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct Token {
     pub kind: TokenKind,
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index ca4a739..e9591c7 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -13,7 +13,7 @@
 //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
-use crate::ast::StmtKind;
+use crate::ast::{AttrStyle, StmtKind};
 use crate::ast_traits::{HasAttrs, HasSpan, HasTokens};
 use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind};
 use crate::AttrVec;
@@ -22,10 +22,11 @@
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
-use std::{fmt, iter, mem};
+use std::borrow::Cow;
+use std::{cmp, fmt, iter, mem};
 
 /// When the main Rust parser encounters a syntax-extension invocation, it
 /// parses the arguments to the invocation as a token tree. This is a very
@@ -98,12 +99,13 @@
         TokenTree::Token(Token::new(kind, span), Spacing::Joint)
     }
 
-    pub fn uninterpolate(self) -> TokenTree {
+    pub fn uninterpolate(&self) -> Cow<'_, TokenTree> {
         match self {
-            TokenTree::Token(token, spacing) => {
-                TokenTree::Token(token.uninterpolate().into_owned(), spacing)
-            }
-            tt => tt,
+            TokenTree::Token(token, spacing) => match token.uninterpolate() {
+                Cow::Owned(token) => Cow::Owned(TokenTree::Token(token, *spacing)),
+                Cow::Borrowed(_) => Cow::Borrowed(self),
+            },
+            _ => Cow::Borrowed(self),
         }
     }
 }
@@ -564,6 +566,92 @@
     pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> {
         self.0.chunks(chunk_size)
     }
+
+    /// Desugar doc comments like `/// foo` in the stream into `#[doc =
+    /// r"foo"]`. Modifies the `TokenStream` via `Lrc::make_mut`, but as little
+    /// as possible.
+    pub fn desugar_doc_comments(&mut self) {
+        if let Some(desugared_stream) = desugar_inner(self.clone()) {
+            *self = desugared_stream;
+        }
+
+        // The return value is `None` if nothing in `stream` changed.
+        fn desugar_inner(mut stream: TokenStream) -> Option<TokenStream> {
+            let mut i = 0;
+            let mut modified = false;
+            while let Some(tt) = stream.0.get(i) {
+                match tt {
+                    &TokenTree::Token(
+                        Token { kind: token::DocComment(_, attr_style, data), span },
+                        _spacing,
+                    ) => {
+                        let desugared = desugared_tts(attr_style, data, span);
+                        let desugared_len = desugared.len();
+                        Lrc::make_mut(&mut stream.0).splice(i..i + 1, desugared);
+                        modified = true;
+                        i += desugared_len;
+                    }
+
+                    &TokenTree::Token(..) => i += 1,
+
+                    &TokenTree::Delimited(sp, delim, ref delim_stream) => {
+                        if let Some(desugared_delim_stream) = desugar_inner(delim_stream.clone()) {
+                            let new_tt = TokenTree::Delimited(sp, delim, desugared_delim_stream);
+                            Lrc::make_mut(&mut stream.0)[i] = new_tt;
+                            modified = true;
+                        }
+                        i += 1;
+                    }
+                }
+            }
+            if modified { Some(stream) } else { None }
+        }
+
+        fn desugared_tts(attr_style: AttrStyle, data: Symbol, span: Span) -> Vec<TokenTree> {
+            // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
+            // required to wrap the text. E.g.
+            // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0)
+            // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1)
+            // - `abc "##d##"` is wrapped as `r###"abc ##"d"##"###` (num_of_hashes = 3)
+            let mut num_of_hashes = 0;
+            let mut count = 0;
+            for ch in data.as_str().chars() {
+                count = match ch {
+                    '"' => 1,
+                    '#' if count > 0 => count + 1,
+                    _ => 0,
+                };
+                num_of_hashes = cmp::max(num_of_hashes, count);
+            }
+
+            // `/// foo` becomes `doc = r"foo"`.
+            let delim_span = DelimSpan::from_single(span);
+            let body = TokenTree::Delimited(
+                delim_span,
+                Delimiter::Bracket,
+                [
+                    TokenTree::token_alone(token::Ident(sym::doc, false), span),
+                    TokenTree::token_alone(token::Eq, span),
+                    TokenTree::token_alone(
+                        TokenKind::lit(token::StrRaw(num_of_hashes), data, None),
+                        span,
+                    ),
+                ]
+                .into_iter()
+                .collect::<TokenStream>(),
+            );
+
+            if attr_style == AttrStyle::Inner {
+                vec![
+                    TokenTree::token_alone(token::Pound, span),
+                    TokenTree::token_alone(token::Not, span),
+                    body,
+                ]
+            } else {
+                vec![TokenTree::token_alone(token::Pound, span), body]
+            }
+        }
+    }
 }
 
 /// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
@@ -595,26 +683,21 @@
     }
 }
 
-/// Owning by-value iterator over a [`TokenStream`], that produces `TokenTree`
+/// Owning by-value iterator over a [`TokenStream`], that produces `&TokenTree`
 /// items.
-// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
+///
+/// Doesn't impl `Iterator` because Rust doesn't permit an owning iterator to
+/// return `&T` from `next`; the need for an explicit lifetime in the `Item`
+/// associated type gets in the way. Instead, use `next_ref` (which doesn't
+/// involve associated types) for getting individual elements, or
+/// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for`
+/// loop.
 #[derive(Clone)]
 pub struct TokenTreeCursor {
     pub stream: TokenStream,
     index: usize,
 }
 
-impl Iterator for TokenTreeCursor {
-    type Item = TokenTree;
-
-    fn next(&mut self) -> Option<TokenTree> {
-        self.stream.0.get(self.index).map(|tree| {
-            self.index += 1;
-            tree.clone()
-        })
-    }
-}
-
 impl TokenTreeCursor {
     fn new(stream: TokenStream) -> Self {
         TokenTreeCursor { stream, index: 0 }
@@ -631,15 +714,6 @@
     pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
         self.stream.0.get(self.index + n)
     }
-
-    // Replace the previously obtained token tree with `tts`, and rewind to
-    // just before them.
-    pub fn replace_prev_and_rewind(&mut self, tts: Vec<TokenTree>) {
-        assert!(self.index > 0);
-        self.index -= 1;
-        let stream = Lrc::make_mut(&mut self.stream.0);
-        stream.splice(self.index..self.index + 1, tts);
-    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index eece99a..bdf5143 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -62,7 +62,7 @@
             CommentKind::Block => {
                 // Whatever happens, we skip the first line.
                 let mut i = lines
-                    .get(0)
+                    .first()
                     .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 })
                     .unwrap_or(0);
                 let mut j = lines.len();
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 096077e..d3e43e2 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -390,7 +390,7 @@
         | ast::ExprKind::Cast(x, _)
         | ast::ExprKind::Type(x, _)
         | ast::ExprKind::Field(x, _)
-        | ast::ExprKind::Index(x, _) => {
+        | ast::ExprKind::Index(x, _, _) => {
             // &X { y: 1 }, X { y: 1 }.y
             contains_exterior_struct_lit(x)
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index d9de5b8..6d474de 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -308,8 +308,12 @@
     match &item.kind {
         ItemKind::ExternCrate(_) => {}
         ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
-        ItemKind::Static(box StaticItem { ty, mutability: _, expr })
-        | ItemKind::Const(box ConstItem { ty, expr, .. }) => {
+        ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
+            visitor.visit_ty(ty);
+            walk_list!(visitor, visit_expr, expr);
+        }
+        ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
+            visitor.visit_generics(generics);
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_expr, expr);
         }
@@ -677,7 +681,8 @@
     visitor.visit_ident(ident);
     walk_list!(visitor, visit_attribute, attrs);
     match kind {
-        AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
+        AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
+            visitor.visit_generics(generics);
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_expr, expr);
         }
@@ -880,7 +885,7 @@
             visitor.visit_expr(subexpression);
             visitor.visit_ident(*ident);
         }
-        ExprKind::Index(main_expression, index_expression) => {
+        ExprKind::Index(main_expression, index_expression, _) => {
             visitor.visit_expr(main_expression);
             visitor.visit_expr(index_expression)
         }
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index d350498..a1e6269 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -207,6 +207,7 @@
                                 &sym.path,
                                 ParamMode::Optional,
                                 &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                                None,
                             );
                             hir::InlineAsmOperand::SymStatic { path, def_id }
                         } else {
@@ -352,7 +353,8 @@
 
                                     let idx2 = *o.get();
                                     let (ref op2, op_sp2) = operands[idx2];
-                                    let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() else {
+                                    let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg()
+                                    else {
                                         unreachable!();
                                     };
 
@@ -368,7 +370,7 @@
                                             assert!(!*late);
                                             let out_op_sp = if input { op_sp2 } else { op_sp };
                                             Some(out_op_sp)
-                                        },
+                                        }
                                         _ => None,
                                     };
 
@@ -377,7 +379,7 @@
                                         op_span2: op_sp2,
                                         reg1_name: reg.name(),
                                         reg2_name: reg2.name(),
-                                        in_out
+                                        in_out,
                                     });
                                 }
                                 Entry::Vacant(v) => {
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 72dc52a..a63bd4f 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -31,9 +31,26 @@
     pub abi: Symbol,
     pub command: String,
     #[subdiagnostic]
+    pub explain: Option<InvalidAbiReason>,
+    #[subdiagnostic]
     pub suggestion: Option<InvalidAbiSuggestion>,
 }
 
+pub struct InvalidAbiReason(pub &'static str);
+
+impl rustc_errors::AddToDiagnostic for InvalidAbiReason {
+    fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
+    where
+        F: Fn(
+            &mut rustc_errors::Diagnostic,
+            rustc_errors::SubdiagnosticMessage,
+        ) -> rustc_errors::SubdiagnosticMessage,
+    {
+        #[allow(rustc::untranslatable_diagnostic)]
+        diag.note(self.0);
+    }
+}
+
 #[derive(Subdiagnostic)]
 #[suggestion(
     ast_lowering_invalid_abi_suggestion,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index dcaaaaf..7408b4f 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -100,6 +100,7 @@
                         ParamMode::Optional,
                         ParenthesizedGenericArgs::Err,
                         &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        None,
                     ));
                     let receiver = self.lower_expr(receiver);
                     let args =
@@ -240,8 +241,8 @@
                 ExprKind::Field(el, ident) => {
                     hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
                 }
-                ExprKind::Index(el, er) => {
-                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
+                ExprKind::Index(el, er, brackets_span) => {
+                    hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
                 }
                 ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => {
                     self.lower_expr_range_closed(e.span, e1, e2)
@@ -260,6 +261,7 @@
                         path,
                         ParamMode::Optional,
                         &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        None,
                     );
                     hir::ExprKind::Path(qpath)
                 }
@@ -286,7 +288,7 @@
                 ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
                     self.lower_ty(
                         container,
-                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
+                        &ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
                     ),
                     self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
                 ),
@@ -307,6 +309,7 @@
                             &se.path,
                             ParamMode::Optional,
                             &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            None,
                         )),
                         self.arena
                             .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -657,14 +660,14 @@
     }
 
     /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to
-    /// `inner_hir_id` in case the `closure_track_caller` feature is enabled.
+    /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled.
     pub(super) fn maybe_forward_track_caller(
         &mut self,
         span: Span,
         outer_hir_id: hir::HirId,
         inner_hir_id: hir::HirId,
     ) {
-        if self.tcx.features().closure_track_caller
+        if self.tcx.features().async_fn_track_caller
             && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
             && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
         {
@@ -1179,6 +1182,7 @@
                         path,
                         ParamMode::Optional,
                         &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        None,
                     );
                     // Destructure like a tuple struct.
                     let tuple_struct_pat = hir::PatKind::TupleStruct(
@@ -1198,6 +1202,7 @@
                         path,
                         ParamMode::Optional,
                         &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        None,
                     );
                     // Destructure like a unit struct.
                     let unit_struct_pat = hir::PatKind::Path(qpath);
@@ -1222,6 +1227,7 @@
                     &se.path,
                     ParamMode::Optional,
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    None,
                 );
                 let fields_omitted = match &se.rest {
                     StructRest::Base(e) => {
@@ -1642,7 +1648,7 @@
         hir::ExprKind::Match(
             scrutinee,
             arena_vec![self; break_arm, continue_arm],
-            hir::MatchSource::TryDesugar,
+            hir::MatchSource::TryDesugar(scrutinee.hir_id),
         )
     }
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ab68436..a59c83d 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,4 +1,4 @@
-use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
+use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
 use super::ResolverAstLoweringExt;
 use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{FnDeclKind, LoweringContext, ParamMode};
@@ -56,6 +56,11 @@
         owner: NodeId,
         f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
     ) {
+        let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller {
+            [sym::gen_future, sym::closure_track_caller][..].into()
+        } else {
+            [sym::gen_future][..].into()
+        });
         let mut lctx = LoweringContext {
             // Pseudo-globals.
             tcx: self.tcx,
@@ -83,8 +88,9 @@
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
-            allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
+            allow_gen_future,
             generics_def_id_map: Default::default(),
+            host_param_id: None,
         };
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
 
@@ -139,8 +145,24 @@
             // This is used to track which lifetimes have already been defined,
             // and which need to be replicated when lowering an async fn.
 
-            if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind {
-                lctx.is_in_trait_impl = impl_.of_trait.is_some();
+            match parent_hir.node().expect_item().kind {
+                hir::ItemKind::Impl(impl_) => {
+                    lctx.is_in_trait_impl = impl_.of_trait.is_some();
+                }
+                hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
+                    lctx.host_param_id = generics
+                        .params
+                        .iter()
+                        .find(|param| {
+                            parent_hir
+                                .attrs
+                                .get(param.hir_id.local_id)
+                                .iter()
+                                .any(|attr| attr.has_name(sym::rustc_host))
+                        })
+                        .map(|param| param.def_id);
+                }
+                _ => {}
             }
 
             match ctxt {
@@ -231,9 +253,15 @@
                 let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
                 hir::ItemKind::Static(ty, *m, body_id)
             }
-            ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
-                let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
-                hir::ItemKind::Const(ty, body_id)
+            ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
+                let (generics, (ty, body_id)) = self.lower_generics(
+                    generics,
+                    Const::No,
+                    id,
+                    &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_const_item(ty, span, expr.as_deref()),
+                );
+                hir::ItemKind::Const(ty, generics, body_id)
             }
             ItemKind::Fn(box Fn {
                 sig: FnSig { decl, header, span: fn_sig_span },
@@ -378,6 +406,7 @@
                     self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
+                                *constness,
                                 trait_ref,
                                 &ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
                             )
@@ -408,7 +437,6 @@
                     polarity,
                     defaultness,
                     defaultness_span,
-                    constness: self.lower_constness(*constness),
                     generics,
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
@@ -551,17 +579,6 @@
                 for &(ref use_tree, id) in trees {
                     let new_hir_id = self.local_def_id(id);
 
-                    let mut prefix = prefix.clone();
-
-                    // Give the segments new node-ids since they are being cloned.
-                    for seg in &mut prefix.segments {
-                        // Give the cloned segment the same resolution information
-                        // as the old one (this is needed for stability checking).
-                        let new_id = self.next_node_id();
-                        self.resolver.clone_res(seg.id, new_id);
-                        seg.id = new_id;
-                    }
-
                     // Each `use` import is an item and thus are owners of the
                     // names in the path. Up to this point the nested import is
                     // the current owner, since we want each desugared import to
@@ -570,6 +587,9 @@
                     self.with_hir_id_owner(id, |this| {
                         let mut ident = *ident;
 
+                        // `prefix` is lowered multiple times, but in different HIR owners.
+                        // So each segment gets renewed `HirId` with the same
+                        // `ItemLocalId` and the new owner. (See `lower_node_id`)
                         let kind =
                             this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs);
                         if let Some(attrs) = attrs {
@@ -723,11 +743,23 @@
         let trait_item_def_id = hir_id.expect_owner();
 
         let (generics, kind, has_default) = match &i.kind {
-            AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
-                let ty =
-                    self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
-                let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
-                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
+            AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
+                let (generics, kind) = self.lower_generics(
+                    &generics,
+                    Const::No,
+                    i.id,
+                    &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| {
+                        let ty = this.lower_ty(
+                            ty,
+                            &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
+                        );
+                        let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
+
+                        hir::TraitItemKind::Const(ty, body)
+                    },
+                );
+                (generics, kind, expr.is_some())
             }
             AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
                 let asyncness = sig.header.asyncness;
@@ -825,14 +857,19 @@
         self.lower_attrs(hir_id, &i.attrs);
 
         let (generics, kind) = match &i.kind {
-            AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
-                let ty =
-                    self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
-                (
-                    hir::Generics::empty(),
-                    hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
-                )
-            }
+            AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
+                &generics,
+                Const::No,
+                i.id,
+                &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                |this| {
+                    let ty = this
+                        .lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
+                    let body = this.lower_const_body(i.span, expr.as_deref());
+
+                    hir::ImplItemKind::Const(ty, body)
+                },
+            ),
             AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
                 self.current_item = Some(i.span);
                 let asyncness = sig.header.asyncness;
@@ -1234,8 +1271,8 @@
     }
 
     pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi {
-        abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|| {
-            self.error_on_invalid_abi(abi);
+        abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
+            self.error_on_invalid_abi(abi, err);
             abi::Abi::Rust
         })
     }
@@ -1248,7 +1285,7 @@
         }
     }
 
-    fn error_on_invalid_abi(&self, abi: StrLit) {
+    fn error_on_invalid_abi(&self, abi: StrLit, err: abi::AbiUnsupported) {
         let abi_names = abi::enabled_names(self.tcx.features(), abi.span)
             .iter()
             .map(|s| Symbol::intern(s))
@@ -1257,6 +1294,10 @@
         self.tcx.sess.emit_err(InvalidAbi {
             abi: abi.symbol_unescaped,
             span: abi.span,
+            explain: match err {
+                abi::AbiUnsupported::Reason { explain } => Some(InvalidAbiReason(explain)),
+                _ => None,
+            },
             suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion {
                 span: abi.span,
                 suggestion: format!("\"{suggested_name}\""),
@@ -1343,6 +1384,29 @@
             }
         }
 
+        // Desugar `~const` bound in generics into an additional `const host: bool` param
+        // if the effects feature is enabled. This needs to be done before we lower where
+        // clauses since where clauses need to bind to the DefId of the host param
+        let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects {
+            if let Some(param) = generics.params.iter().find(|x| {
+                x.attrs.iter().any(|x| x.has_name(sym::rustc_host))
+            }) {
+                // user has manually specified a `rustc_host` param, in this case, we set
+                // the param id so that lowering logic can use that. But we don't create
+                // another host param, so this gives `None`.
+                self.host_param_id = Some(self.local_def_id(param.id));
+                None
+            } else {
+                let param_node_id = self.next_node_id();
+                let hir_id = self.next_id();
+                let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
+                self.host_param_id = Some(def_id);
+                Some((span, hir_id, def_id))
+            }
+        } else {
+            None
+        };
+
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
             self.lower_generic_bound_predicate(
@@ -1390,22 +1454,11 @@
         let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
         predicates.extend(impl_trait_bounds.into_iter());
 
-        // Desugar `~const` bound in generics into an additional `const host: bool` param
-        // if the effects feature is enabled.
-        if let Const::Yes(span) = constness && self.tcx.features().effects
-            // Do not add host param if it already has it (manually specified)
-            && !params.iter().any(|x| {
-                self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
-                    attrs.iter().any(|x| x.has_name(sym::rustc_host))
-                })
-            })
-        {
-            let param_node_id = self.next_node_id();
+        if let Some((span, hir_id, def_id)) = host_param_parts {
             let const_node_id = self.next_node_id();
-            let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
-            let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
+            let anon_const: LocalDefId =
+                self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
 
-            let hir_id = self.next_id();
             let const_id = self.next_id();
             let const_expr_id = self.next_id();
             let bool_id = self.next_id();
@@ -1415,14 +1468,15 @@
 
             let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
 
-            let attrs = self.arena.alloc_from_iter([
-                Attribute {
-                    kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
+            let attrs = self.arena.alloc_from_iter([Attribute {
+                kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(
+                    sym::rustc_host,
                     span,
-                    id: attr_id,
-                    style: AttrStyle::Outer,
-                },
-            ]);
+                )))),
+                span,
+                id: attr_id,
+                style: AttrStyle::Outer,
+            }]);
             self.attrs.insert(hir_id.local_id, attrs);
 
             let const_body = self.lower_body(|this| {
@@ -1461,7 +1515,11 @@
                             }),
                         )),
                     )),
-                    default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
+                    default: Some(hir::AnonConst {
+                        def_id: anon_const,
+                        hir_id: const_id,
+                        body: const_body,
+                    }),
                 },
                 colon_span: None,
                 pure_wrt_drop: false,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 429e62c..4a47de1 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -142,16 +142,14 @@
     /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
     /// field from the original parameter 'a to the new parameter 'a1.
     generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
+
+    host_param_id: Option<LocalDefId>,
 }
 
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
     fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
-    // Clones the resolution (if any) on 'source' and applies it
-    // to 'target'. Used when desugaring a `UseTreeKind::Nested` to
-    // multiple `UseTreeKind::Simple`s
-    fn clone_res(&mut self, source: NodeId, target: NodeId);
     fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
     fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
@@ -184,12 +182,6 @@
         None
     }
 
-    fn clone_res(&mut self, source: NodeId, target: NodeId) {
-        if let Some(res) = self.partial_res_map.get(&source) {
-            self.partial_res_map.insert(target, *res);
-        }
-    }
-
     /// Obtains resolution for a `NodeId` with a single resolution.
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).copied()
@@ -465,7 +457,7 @@
 
     // Don't hash unless necessary, because it's expensive.
     let opt_hir_hash =
-        if tcx.sess.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
+        if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
     hir::Crate { owners, opt_hir_hash }
 }
 
@@ -522,11 +514,6 @@
         self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
     }
 
-    fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
-        self.orig_opt_local_def_id(node)
-            .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
-    }
-
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
     ///
@@ -661,7 +648,7 @@
         let bodies = SortedMap::from_presorted_elements(bodies);
 
         // Don't hash unless necessary, because it's expensive.
-        let (opt_hash_including_bodies, attrs_hash) = if self.tcx.sess.needs_crate_hash() {
+        let (opt_hash_including_bodies, attrs_hash) = if self.tcx.needs_crate_hash() {
             self.tcx.with_stable_hashing_context(|mut hcx| {
                 let mut stable_hasher = StableHasher::new();
                 hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
@@ -1277,6 +1264,7 @@
                         span: t.span
                     },
                     itctx,
+                    ast::Const::No,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
                 let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1287,7 +1275,7 @@
         }
 
         let id = self.lower_node_id(t.id);
-        let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
+        let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None);
         self.ty_path(id, t.span, qpath)
     }
 
@@ -1371,10 +1359,12 @@
                         this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
                             GenericBound::Trait(
                                 ty,
-                                TraitBoundModifier::None
+                                modifier @ (TraitBoundModifier::None
                                 | TraitBoundModifier::MaybeConst
-                                | TraitBoundModifier::Negative,
-                            ) => Some(this.lower_poly_trait_ref(ty, itctx)),
+                                | TraitBoundModifier::Negative),
+                            ) => {
+                                Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
+                            }
                             // `~const ?Bound` will cause an error during AST validation
                             // anyways, so treat it like `?Bound` as compilation proceeds.
                             GenericBound::Trait(
@@ -1531,6 +1521,45 @@
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
+        let captured_lifetimes_to_duplicate = match origin {
+            hir::OpaqueTyOrigin::TyAlias { .. } => {
+                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
+                // lifetimes, since we don't have the issue that any are late-bound.
+                Vec::new()
+            }
+            hir::OpaqueTyOrigin::FnReturn(..) => {
+                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
+                // example, we only need to duplicate lifetimes that appear in the
+                // bounds, since those are the only ones that are captured by the opaque.
+                lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+            }
+            hir::OpaqueTyOrigin::AsyncFn(..) => {
+                unreachable!("should be using `lower_async_fn_ret_ty`")
+            }
+        };
+        debug!(?captured_lifetimes_to_duplicate);
+
+        self.lower_opaque_inner(
+            opaque_ty_node_id,
+            origin,
+            in_trait,
+            captured_lifetimes_to_duplicate,
+            span,
+            opaque_ty_span,
+            |this| this.lower_param_bounds(bounds, itctx),
+        )
+    }
+
+    fn lower_opaque_inner(
+        &mut self,
+        opaque_ty_node_id: NodeId,
+        origin: hir::OpaqueTyOrigin,
+        in_trait: bool,
+        captured_lifetimes_to_duplicate: Vec<Lifetime>,
+        span: Span,
+        opaque_ty_span: Span,
+        lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
+    ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.create_def(
             self.current_hir_id_owner.def_id,
             opaque_ty_node_id,
@@ -1539,199 +1568,39 @@
         );
         debug!(?opaque_ty_def_id);
 
-        // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
-        // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
-        // exactly which ones those are.
-        let lifetimes_to_remap = match origin {
-            hir::OpaqueTyOrigin::TyAlias { .. } => {
-                // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
-                Vec::new()
-            }
-            hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
-                // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-                // we only keep the lifetimes that appear in the `impl Debug` itself:
-                lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
-            }
-        };
-        debug!(?lifetimes_to_remap);
+        // Map from captured (old) lifetime to synthetic (new) lifetime.
+        // Used to resolve lifetimes in the bounds of the opaque.
+        let mut captured_to_synthesized_mapping = FxHashMap::default();
+        // List of (early-bound) synthetic lifetimes that are owned by the opaque.
+        // This is used to create the `hir::Generics` owned by the opaque.
+        let mut synthesized_lifetime_definitions = vec![];
+        // Pairs of lifetime arg (that resolves to the captured lifetime)
+        // and the def-id of the (early-bound) synthetic lifetime definition.
+        // This is used both to create generics for the `TyKind::OpaqueDef` that
+        // we return, and also as a captured lifetime mapping for RPITITs.
+        let mut synthesized_lifetime_args = vec![];
 
-        let mut new_remapping = FxHashMap::default();
-
-        // Contains the new lifetime definitions created for the TAIT (if any).
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        let collected_lifetimes =
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime)| {
-                let id = self.next_node_id();
-                let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
-            .collect();
-        debug!(?collected_lifetime_mapping);
-
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            // Install the remapping from old to new (if any):
-            lctx.with_remapping(new_remapping, |lctx| {
-                // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
-                // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
-                // containing `&['x]`.
-                let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime)| {
-                        let hir_id = lctx.lower_node_id(new_node_id);
-                        debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
-
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: lctx.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!(?lifetime_defs);
-
-                // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
-                // get back Debug + 'a1, which is suitable for use on the TAIT.
-                let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
-                debug!(?hir_bounds);
-
-                let lifetime_mapping = if in_trait {
-                    self.arena.alloc_from_iter(
-                        collected_lifetime_mapping
-                            .iter()
-                            .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                    )
-                } else {
-                    &mut []
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: self.arena.alloc(hir::Generics {
-                        params: lifetime_defs,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: lctx.lower_span(span),
-                        span: lctx.lower_span(span),
-                    }),
-                    bounds: hir_bounds,
-                    origin,
-                    lifetime_mapping,
-                    in_trait,
-                };
-                debug!(?opaque_ty_item);
-
-                lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            self.arena.alloc_from_iter(
-                collected_lifetime_mapping
-                    .iter()
-                    .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
-            ),
-            in_trait,
-        )
-    }
-
-    /// Registers a new opaque type with the proper `NodeId`s and
-    /// returns the lowered node-ID for the opaque type.
-    fn generate_opaque_type(
-        &mut self,
-        opaque_ty_id: LocalDefId,
-        opaque_ty_item: hir::OpaqueTy<'hir>,
-        span: Span,
-        opaque_ty_span: Span,
-    ) -> hir::OwnerNode<'hir> {
-        let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
-        // Generate an `type Foo = impl Trait;` declaration.
-        trace!("registering opaque type with id {:#?}", opaque_ty_id);
-        let opaque_ty_item = hir::Item {
-            owner_id: hir::OwnerId { def_id: opaque_ty_id },
-            ident: Ident::empty(),
-            kind: opaque_ty_item_kind,
-            vis_span: self.lower_span(span.shrink_to_lo()),
-            span: self.lower_span(opaque_ty_span),
-        };
-        hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
-    }
-
-    /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
-    /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
-    /// new definition, adds it to the remapping with the definition of the given lifetime and
-    /// returns a list of lifetimes to be lowered afterwards.
-    fn create_lifetime_defs(
-        &mut self,
-        parent_def_id: LocalDefId,
-        lifetimes_in_bounds: &[Lifetime],
-        remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
-    ) -> Vec<(NodeId, Lifetime)> {
-        let mut result = Vec::new();
-
-        for lifetime in lifetimes_in_bounds {
+        for lifetime in captured_lifetimes_to_duplicate {
             let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
-            debug!(?res);
-
-            match res {
-                LifetimeRes::Param { param: old_def_id, binder: _ } => {
-                    if remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(lifetime.ident.name),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
-                    }
-                }
+            let old_def_id = match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
-                        let node_id = self.next_node_id();
-
-                        let new_def_id = self.create_def(
-                            parent_def_id,
-                            node_id,
-                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                            lifetime.ident.span,
-                        );
-                        remapping.insert(old_def_id, new_def_id);
-
-                        result.push((node_id, *lifetime));
+                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
+                        old_def_id
+                    } else {
+                        self.tcx
+                            .sess
+                            .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime");
+                        continue;
                     }
                 }
 
-                LifetimeRes::Static | LifetimeRes::Error => {}
+                // Opaques do not capture `'static`
+                LifetimeRes::Static | LifetimeRes::Error => {
+                    continue;
+                }
 
                 res => {
                     let bug_msg = format!(
@@ -1740,10 +1609,109 @@
                     );
                     span_bug!(lifetime.ident.span, "{}", bug_msg);
                 }
+            };
+
+            if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
+                // Create a new lifetime parameter local to the opaque.
+                let duplicated_lifetime_node_id = self.next_node_id();
+                let duplicated_lifetime_def_id = self.create_def(
+                    opaque_ty_def_id,
+                    duplicated_lifetime_node_id,
+                    DefPathData::LifetimeNs(lifetime.ident.name),
+                    lifetime.ident.span,
+                );
+                captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
+                // FIXME: Instead of doing this, we could move this whole loop
+                // into the `with_hir_id_owner`, then just directly construct
+                // the `hir::GenericParam` here.
+                synthesized_lifetime_definitions.push((
+                    duplicated_lifetime_node_id,
+                    duplicated_lifetime_def_id,
+                    lifetime.ident,
+                ));
+
+                // Now make an arg that we can use for the substs of the opaque tykind.
+                let id = self.next_node_id();
+                let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
+                let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
+                synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
             }
         }
 
-        result
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+            // Install the remapping from old to new (if any). This makes sure that
+            // any lifetimes that would have resolved to the def-id of captured
+            // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
+            let bounds = this
+                .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
+
+            let generic_params = this.arena.alloc_from_iter(
+                synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
+                    let hir_id = this.lower_node_id(new_node_id);
+                    let (name, kind) = if ident.name == kw::UnderscoreLifetime {
+                        (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                    } else {
+                        (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
+                    };
+
+                    hir::GenericParam {
+                        hir_id,
+                        def_id: new_def_id,
+                        name,
+                        span: ident.span,
+                        pure_wrt_drop: false,
+                        kind: hir::GenericParamKind::Lifetime { kind },
+                        colon_span: None,
+                        source: hir::GenericParamSource::Generics,
+                    }
+                }),
+            );
+            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+            let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
+
+            let opaque_ty_item = hir::OpaqueTy {
+                generics: this.arena.alloc(hir::Generics {
+                    params: generic_params,
+                    predicates: &[],
+                    has_where_clause_predicates: false,
+                    where_clause_span: this.lower_span(span),
+                    span: this.lower_span(span),
+                }),
+                bounds,
+                origin,
+                lifetime_mapping,
+                in_trait,
+            };
+
+            // Generate an `type Foo = impl Trait;` declaration.
+            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let opaque_ty_item = hir::Item {
+                owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
+                ident: Ident::empty(),
+                kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
+                vis_span: this.lower_span(span.shrink_to_lo()),
+                span: this.lower_span(opaque_ty_span),
+            };
+
+            hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
+        });
+
+        let generic_args = self.arena.alloc_from_iter(
+            synthesized_lifetime_args
+                .iter()
+                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+        );
+
+        // Create the `Foo<...>` reference itself. Note that the `type
+        // Foo = impl Trait` is, internally, created as a child of the
+        // async fn, so the *type parameters* are inherited. It's
+        // only the lifetime parameters that we must supply.
+        hir::TyKind::OpaqueDef(
+            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+            generic_args,
+            in_trait,
+        )
     }
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
@@ -1821,9 +1789,10 @@
                 }
             }
 
+            let fn_def_id = self.local_def_id(fn_node_id);
             self.lower_async_fn_ret_ty(
                 &decl.output,
-                fn_node_id,
+                fn_def_id,
                 ret_id,
                 matches!(kind, FnDeclKind::Trait),
             )
@@ -1900,151 +1869,28 @@
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
-        fn_node_id: NodeId,
+        fn_def_id: LocalDefId,
         opaque_ty_node_id: NodeId,
         in_trait: bool,
     ) -> hir::FnRetTy<'hir> {
-        let span = output.span();
-
+        let span = self.lower_span(output.span());
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
 
-        let fn_def_id = self.local_def_id(fn_node_id);
-
-        let opaque_ty_def_id =
-            self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
-
-        // When we create the opaque type for this async fn, it is going to have
-        // to capture all the lifetimes involved in the signature (including in the
-        // return type). This is done by introducing lifetime parameters for:
-        //
-        // - all the explicitly declared lifetimes from the impl and function itself;
-        // - all the elided lifetimes in the fn arguments;
-        // - all the elided lifetimes in the return type.
-        //
-        // So for example in this snippet:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
-        //   //               ^ '0                       ^ '1     ^ '2
-        //   // elided lifetimes used below
-        //   }
-        // }
-        // ```
-        //
-        // we would create an opaque type like:
-        //
-        // ```
-        // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
-        // ```
-        //
-        // and we would then desugar `bar` to the equivalent of:
-        //
-        // ```rust
-        // impl<'a> Foo<'a> {
-        //   fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
-        // }
-        // ```
-        //
-        // Note that the final parameter to `Bar` is `'_`, not `'2` --
-        // this is because the elided lifetimes from the return type
-        // should be figured out using the ordinary elision rules, and
-        // this desugaring achieves that.
-
-        // Calculate all the lifetimes that should be captured
-        // by the opaque type. This should include all in-scope
-        // lifetime parameters, including those defined in-band.
-
-        // Contains the new lifetime definitions created for the TAIT (if any) generated for the
-        // return type.
-        let mut collected_lifetimes = Vec::new();
-        let mut new_remapping = FxHashMap::default();
-
-        let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
-        debug!(?extra_lifetime_params);
-        for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let outer_def_id = self.orig_local_def_id(outer_node_id);
-            let inner_node_id = self.next_node_id();
-
-            // Add a definition for the in scope lifetime def.
-            let inner_def_id = self.create_def(
-                opaque_ty_def_id,
-                inner_node_id,
-                DefPathData::LifetimeNs(ident.name),
-                ident.span,
-            );
-            new_remapping.insert(outer_def_id, inner_def_id);
-
-            let inner_res = match outer_res {
-                // Input lifetime like `'a`:
-                LifetimeRes::Param { param, .. } => {
-                    LifetimeRes::Param { param, binder: fn_node_id }
-                }
-                // Input lifetime like `'1`:
-                LifetimeRes::Fresh { param, .. } => {
-                    LifetimeRes::Fresh { param, binder: fn_node_id }
-                }
-                LifetimeRes::Static | LifetimeRes::Error => continue,
-                res => {
-                    panic!(
-                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
-                        res, ident, ident.span
-                    )
-                }
-            };
-
-            let lifetime = Lifetime { id: outer_node_id, ident };
-            collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
-        }
-        debug!(?collected_lifetimes);
-
-        // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
-        // find out exactly which ones those are.
-        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
-        // we only keep the lifetimes that appear in the `impl Debug` itself:
-        let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
-        debug!(?lifetimes_to_remap);
-
-        // If this opaque type is only capturing a subset of the lifetimes (those that appear in
-        // bounds), then create the new lifetime parameters required and create a mapping from the
-        // old `'a` (on the function) to the new `'a` (on the opaque type).
-        collected_lifetimes.extend(
-            self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
-                .into_iter()
-                .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
-        );
-        debug!(?collected_lifetimes);
-        debug!(?new_remapping);
-
-        // This creates pairs of HIR lifetimes and def_ids. In the given example `type
-        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
-        // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
-        // `TestReturn`.
-        let collected_lifetime_mapping: Vec<_> = collected_lifetimes
-            .iter()
-            .map(|(node_id, lifetime, res)| {
-                let id = self.next_node_id();
-                let res = res.unwrap_or(
-                    self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
-                );
-                let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
-                let def_id = self.local_def_id(*node_id);
-                (lifetime, def_id)
-            })
+        let captured_lifetimes: Vec<_> = self
+            .resolver
+            .take_extra_lifetime_params(opaque_ty_node_id)
+            .into_iter()
+            .map(|(ident, id, _)| Lifetime { id, ident })
             .collect();
-        debug!(?collected_lifetime_mapping);
 
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            // Install the remapping from old to new (if any):
-            this.with_remapping(new_remapping, |this| {
-                // We have to be careful to get elision right here. The
-                // idea is that we create a lifetime parameter for each
-                // lifetime in the return type. So, given a return type
-                // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-                // Future<Output = &'1 [ &'2 u32 ]>`.
-                //
-                // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-                // hence the elision takes place at the fn site.
+        let opaque_ty_ref = self.lower_opaque_inner(
+            opaque_ty_node_id,
+            hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+            in_trait,
+            captured_lifetimes,
+            span,
+            opaque_ty_span,
+            |this| {
                 let future_bound = this.lower_async_fn_output_type_to_future_bound(
                     output,
                     span,
@@ -2060,94 +1906,10 @@
                         }
                     },
                 );
-
-                let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                    |&(new_node_id, lifetime, _)| {
-                        let hir_id = this.lower_node_id(new_node_id);
-                        debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
-
-                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
-                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                        } else {
-                            (
-                                hir::ParamName::Plain(lifetime.ident),
-                                hir::LifetimeParamKind::Explicit,
-                            )
-                        };
-
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: this.local_def_id(new_node_id),
-                            name,
-                            span: lifetime.ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-                debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-                let lifetime_mapping = if in_trait {
-                    self.arena.alloc_from_iter(
-                        collected_lifetime_mapping
-                            .iter()
-                            .map(|(lifetime, def_id)| (**lifetime, *def_id)),
-                    )
-                } else {
-                    &mut []
-                };
-
-                let opaque_ty_item = hir::OpaqueTy {
-                    generics: this.arena.alloc(hir::Generics {
-                        params: generic_params,
-                        predicates: &[],
-                        has_where_clause_predicates: false,
-                        where_clause_span: this.lower_span(span),
-                        span: this.lower_span(span),
-                    }),
-                    bounds: arena_vec![this; future_bound],
-                    origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-                    lifetime_mapping,
-                    in_trait,
-                };
-
-                trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-                this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
-            })
-        });
-
-        // As documented above, we need to create the lifetime
-        // arguments to our opaque type. Continuing with our example,
-        // we're creating the type arguments for the return type:
-        //
-        // ```
-        // Bar<'a, 'b, '0, '1, '_>
-        // ```
-        //
-        // For the "input" lifetime parameters, we wish to create
-        // references to the parameters themselves, including the
-        // "implicit" ones created from parameter types (`'a`, `'b`,
-        // '`0`, `'1`).
-        //
-        // For the "output" lifetime parameters, we just want to
-        // generate `'_`.
-        let generic_args = self.arena.alloc_from_iter(
-            collected_lifetime_mapping
-                .iter()
-                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
+                arena_vec![this; future_bound]
+            },
         );
 
-        // Create the `Foo<...>` reference itself. Note that the `type
-        // Foo = impl Trait` is, internally, created as a child of the
-        // async fn, so the *type parameters* are inherited. It's
-        // only the lifetime parameters that we must supply.
-        let opaque_ty_ref = hir::TyKind::OpaqueDef(
-            hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
-            generic_args,
-            in_trait,
-        );
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
@@ -2195,7 +1957,7 @@
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
-                self.lower_poly_trait_ref(p, itctx),
+                self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
                 self.lower_trait_bound_modifier(*modifier),
             ),
             GenericBound::Outlives(lifetime) => {
@@ -2338,8 +2100,20 @@
         }
     }
 
-    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
-        let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
+    fn lower_trait_ref(
+        &mut self,
+        constness: ast::Const,
+        p: &TraitRef,
+        itctx: &ImplTraitContext,
+    ) -> hir::TraitRef<'hir> {
+        let path = match self.lower_qpath(
+            p.ref_id,
+            &None,
+            &p.path,
+            ParamMode::Explicit,
+            itctx,
+            Some(constness),
+        ) {
             hir::QPath::Resolved(None, path) => path,
             qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
         };
@@ -2351,10 +2125,11 @@
         &mut self,
         p: &PolyTraitRef,
         itctx: &ImplTraitContext,
+        constness: ast::Const,
     ) -> hir::PolyTraitRef<'hir> {
         let bound_generic_params =
             self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
-        let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+        let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
         hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
     }
 
@@ -2708,6 +2483,63 @@
 }
 
 impl<'hir> GenericArgsCtor<'hir> {
+    fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
+        if !lcx.tcx.features().effects {
+            return;
+        }
+
+        // if bound is non-const, don't add host effect param
+        let ast::Const::Yes(span) = constness else { return };
+
+        let span = lcx.lower_span(span);
+
+        let id = lcx.next_node_id();
+        let hir_id = lcx.next_id();
+
+        let Some(host_param_id) = lcx.host_param_id else {
+            lcx.tcx
+                .sess
+                .delay_span_bug(span, "no host param id for call in const yet no errors reported");
+            return;
+        };
+
+        let body = lcx.lower_body(|lcx| {
+            (&[], {
+                let hir_id = lcx.next_id();
+                let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
+                let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
+                    None,
+                    lcx.arena.alloc(hir::Path {
+                        span,
+                        res,
+                        segments: arena_vec![lcx; hir::PathSegment::new(Ident {
+                            name: sym::host,
+                            span,
+                        }, hir_id, res)],
+                    }),
+                ));
+                lcx.expr(span, expr_kind)
+            })
+        });
+
+        let attr_id = lcx.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
+        let attr = lcx.arena.alloc(Attribute {
+            kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
+            span,
+            id: attr_id,
+            style: AttrStyle::Outer,
+        });
+        lcx.attrs.insert(hir_id.local_id, std::slice::from_ref(attr));
+
+        let def_id =
+            lcx.create_def(lcx.current_hir_id_owner.def_id, id, DefPathData::AnonConst, span);
+        lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
+        self.args.push(hir::GenericArg::Const(hir::ConstArg {
+            value: hir::AnonConst { def_id, hir_id, body },
+            span,
+        }))
+    }
+
     fn is_empty(&self) -> bool {
         self.args.is_empty()
             && self.bindings.is_empty()
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 3989fc4..6f75419 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,7 +1,7 @@
 use super::ResolverAstLoweringExt;
 use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
-use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
-use rustc_hir::def::LifetimeRes;
+use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_hir::def::{DefKind, LifetimeRes, Res};
 use rustc_middle::span_bug;
 use rustc_middle::ty::ResolverAstLowering;
 use rustc_span::symbol::{kw, Ident};
@@ -77,7 +77,20 @@
     }
 
     fn visit_ty(&mut self, t: &'ast Ty) {
-        match t.kind {
+        match &t.kind {
+            TyKind::Path(None, _) => {
+                // We can sometimes encounter bare trait objects
+                // which are represented in AST as paths.
+                if let Some(partial_res) = self.resolver.get_partial_res(t.id)
+                    && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
+                {
+                    self.current_binders.push(t.id);
+                    visit::walk_ty(self, t);
+                    self.current_binders.pop();
+                } else {
+                    visit::walk_ty(self, t);
+                }
+            }
             TyKind::BareFn(_) => {
                 self.current_binders.push(t.id);
                 visit::walk_ty(self, t);
@@ -94,12 +107,6 @@
     }
 }
 
-pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
-    let mut visitor = LifetimeCollectVisitor::new(resolver);
-    visitor.visit_fn_ret_ty(ret_ty);
-    visitor.collected_lifetimes
-}
-
 pub fn lifetimes_in_bounds(
     resolver: &ResolverAstLowering,
     bounds: &GenericBounds,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 2509b70..a30f264 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -38,6 +38,7 @@
                             path,
                             ParamMode::Optional,
                             &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            None,
                         );
                         let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
                         break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -54,6 +55,7 @@
                             path,
                             ParamMode::Optional,
                             &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            None,
                         );
                         break hir::PatKind::Path(qpath);
                     }
@@ -64,6 +66,7 @@
                             path,
                             ParamMode::Optional,
                             &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            None,
                         );
 
                         let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 441282c..899f92a 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -23,6 +23,8 @@
         p: &Path,
         param_mode: ParamMode,
         itctx: &ImplTraitContext,
+        // constness of the impl/bound if this is a trait path
+        constness: Option<ast::Const>,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
         let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -73,6 +75,8 @@
                         param_mode,
                         parenthesized_generic_args,
                         itctx,
+                        // if this is the last segment, add constness to the trait path
+                        if i == proj_start - 1 { constness } else { None },
                     )
                 },
             )),
@@ -119,6 +123,7 @@
                 param_mode,
                 ParenthesizedGenericArgs::Err,
                 itctx,
+                None,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
 
@@ -159,6 +164,7 @@
                     param_mode,
                     ParenthesizedGenericArgs::Err,
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    None,
                 )
             })),
             span: self.lower_span(p.span),
@@ -172,8 +178,9 @@
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: &ImplTraitContext,
+        constness: Option<ast::Const>,
     ) -> hir::PathSegment<'hir> {
-        debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
+        debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
         let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
             match generic_args {
                 GenericArgs::AngleBracketed(data) => {
@@ -231,6 +238,10 @@
             )
         };
 
+        if let Some(constness) = constness {
+            generic_args.push_constness(self, constness);
+        }
+
         let has_lifetimes =
             generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
 
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 2f0ac0c..f323bb4 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -239,5 +239,10 @@
     .individual_impl_items = place qualifiers on individual impl items instead
     .individual_foreign_items = place qualifiers on individual foreign items instead
 
-ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
+    .note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+    .help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
+
+ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
     .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+    .suggestion = move it to the end of the type declaration
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 096cea9..bd3e676 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,6 +13,7 @@
 use rustc_ast::{walk_list, StaticItem};
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_feature::Features;
 use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
@@ -45,6 +46,7 @@
 
 struct AstValidator<'a> {
     session: &'a Session,
+    features: &'a Features,
 
     /// The span of the `extern` in an `extern { ... }` block, if any.
     extern_mod: Option<&'a Item>,
@@ -136,40 +138,42 @@
         }
     }
 
-    fn check_gat_where(
+    fn check_type_alias_where_clause_location(
         &mut self,
-        id: NodeId,
-        before_predicates: &[WherePredicate],
-        where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
-    ) {
-        if !before_predicates.is_empty() {
-            let mut state = State::new();
-            if !where_clauses.1.0 {
-                state.space();
-                state.word_space("where");
-            } else {
+        ty_alias: &TyAlias,
+    ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
+        let before_predicates =
+            ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
+
+        if ty_alias.ty.is_none() || before_predicates.is_empty() {
+            return Ok(());
+        }
+
+        let mut state = State::new();
+        if !ty_alias.where_clauses.1.0 {
+            state.space();
+            state.word_space("where");
+        } else {
+            state.word_space(",");
+        }
+        let mut first = true;
+        for p in before_predicates {
+            if !first {
                 state.word_space(",");
             }
-            let mut first = true;
-            for p in before_predicates.iter() {
-                if !first {
-                    state.word_space(",");
-                }
-                first = false;
-                state.print_where_predicate(p);
-            }
-            let suggestion = state.s.eof();
-            self.lint_buffer.buffer_lint_with_diagnostic(
-                DEPRECATED_WHERE_CLAUSE_LOCATION,
-                id,
-                where_clauses.0.1,
-                fluent::ast_passes_deprecated_where_clause_location,
-                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
-                    where_clauses.1.1.shrink_to_hi(),
-                    suggestion,
-                ),
-            );
+            first = false;
+            state.print_where_predicate(p);
         }
+
+        let span = ty_alias.where_clauses.0.1;
+        Err(errors::WhereClauseBeforeTypeAlias {
+            span,
+            sugg: errors::WhereClauseBeforeTypeAliasSugg {
+                left: span,
+                snippet: state.s.eof(),
+                right: ty_alias.where_clauses.1.1.shrink_to_hi(),
+            },
+        })
     }
 
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@@ -659,7 +663,7 @@
             GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
             GenericParamKind::Const { ty, .. } => {
                 let ty = pprust::ty_to_string(ty);
-                (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
+                (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))
             }
         };
         param_idents.push((kind, ord_kind, bounds, idx, ident));
@@ -1009,7 +1013,9 @@
                     replace_span: self.ending_semi_or_hi(item.span),
                 });
             }
-            ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
+            ItemKind::TyAlias(
+                ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
+            ) => {
                 self.check_defaultness(item.span, *defaultness);
                 if ty.is_none() {
                     self.session.emit_err(errors::TyAliasWithoutBody {
@@ -1018,9 +1024,16 @@
                     });
                 }
                 self.check_type_no_bounds(bounds, "this context");
-                if where_clauses.1.0 {
-                    self.err_handler()
-                        .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
+
+                if self.features.lazy_type_alias {
+                    if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
+                        self.err_handler().emit_err(err);
+                    }
+                } else if where_clauses.1.0 {
+                    self.err_handler().emit_err(errors::WhereClauseAfterTypeAlias {
+                        span: where_clauses.1.1,
+                        help: self.session.is_nightly_build().then_some(()),
+                    });
                 }
             }
             _ => {}
@@ -1300,14 +1313,7 @@
                         });
                     }
                 }
-                AssocItemKind::Type(box TyAlias {
-                    generics,
-                    where_clauses,
-                    where_predicates_split,
-                    bounds,
-                    ty,
-                    ..
-                }) => {
+                AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
                     if ty.is_none() {
                         self.session.emit_err(errors::AssocTypeWithoutBody {
                             span: item.span,
@@ -1315,18 +1321,26 @@
                         });
                     }
                     self.check_type_no_bounds(bounds, "`impl`s");
-                    if ty.is_some() {
-                        self.check_gat_where(
-                            item.id,
-                            generics.where_clause.predicates.split_at(*where_predicates_split).0,
-                            *where_clauses,
-                        );
-                    }
                 }
                 _ => {}
             }
         }
 
+        if let AssocItemKind::Type(ty_alias) = &item.kind
+            && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
+        {
+            self.lint_buffer.buffer_lint_with_diagnostic(
+                DEPRECATED_WHERE_CLAUSE_LOCATION,
+                item.id,
+                err.span,
+                fluent::ast_passes_deprecated_where_clause_location,
+                BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
+                    err.sugg.right,
+                    err.sugg.snippet,
+                ),
+            );
+        }
+
         if ctxt == AssocCtxt::Trait || self.in_trait_impl {
             self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
             if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
@@ -1462,15 +1476,12 @@
                                             let Some(arg) = args.args.last() else {
                                                 continue;
                                             };
-                                            (
-                                                format!(", {} = {}", assoc, ty),
-                                                arg.span().shrink_to_hi(),
-                                            )
+                                            (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
                                         }
                                         _ => continue,
                                     },
                                     None => (
-                                        format!("<{} = {}>", assoc, ty),
+                                        format!("<{assoc} = {ty}>"),
                                         trait_segment.span().shrink_to_hi(),
                                     ),
                                 };
@@ -1491,9 +1502,15 @@
     this.err_handler().emit_err(err);
 }
 
-pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
+pub fn check_crate(
+    session: &Session,
+    features: &Features,
+    krate: &Crate,
+    lints: &mut LintBuffer,
+) -> bool {
     let mut validator = AstValidator {
         session,
+        features,
         extern_mod: None,
         in_trait_impl: false,
         in_const_trait_impl: false,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ab8015c..a6f217d 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -496,11 +496,37 @@
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_where_after_type_alias)]
+#[diag(ast_passes_where_clause_after_type_alias)]
 #[note]
-pub struct WhereAfterTypeAlias {
+pub struct WhereClauseAfterTypeAlias {
     #[primary_span]
     pub span: Span,
+    #[help]
+    pub help: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_where_clause_before_type_alias)]
+#[note]
+pub struct WhereClauseBeforeTypeAlias {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub sugg: WhereClauseBeforeTypeAliasSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    ast_passes_suggestion,
+    applicability = "machine-applicable",
+    style = "verbose"
+)]
+pub struct WhereClauseBeforeTypeAliasSugg {
+    #[suggestion_part(code = "")]
+    pub left: Span,
+    pub snippet: String,
+    #[suggestion_part(code = "{snippet}")]
+    pub right: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b0dbc2c..10c9c3e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -218,6 +218,19 @@
                 }
             }
         }
+        if !attr.is_doc_comment()
+            && attr.get_normal_item().path.segments.len() == 2
+            && attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic
+            && !self.features.diagnostic_namespace
+        {
+            let msg = "`#[diagnostic]` attribute name space is experimental";
+            gate_feature_post!(
+                self,
+                diagnostic_namespace,
+                attr.get_normal_item().path.segments[0].ident.span,
+                msg
+            );
+        }
 
         // Emit errors for non-staged-api crates.
         if !self.features.staged_api {
@@ -501,10 +514,10 @@
     }
 }
 
-pub fn check_crate(krate: &ast::Crate, sess: &Session) {
-    maybe_stage_features(sess, krate);
-    check_incompatible_features(sess);
-    let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
+pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
+    maybe_stage_features(sess, features, krate);
+    check_incompatible_features(sess, features);
+    let mut visitor = PostExpansionVisitor { sess, features };
 
     let spans = sess.parse_sess.gated_spans.spans.borrow();
     macro_rules! gate_all {
@@ -556,6 +569,7 @@
     gate_all!(const_closures, "const closures are experimental");
     gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
     gate_all!(explicit_tail_calls, "`become` expression is experimental");
+    gate_all!(generic_const_items, "generic const items are experimental");
 
     if !visitor.features.negative_bounds {
         for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
@@ -586,12 +600,12 @@
     visit::walk_crate(&mut visitor, krate);
 }
 
-fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
     // checks if `#![feature]` has been used to enable any lang feature
     // does not check the same for lib features unless there's at least one
     // declared lang feature
     if !sess.opts.unstable_features.is_nightly_build() {
-        let lang_features = &sess.features_untracked().declared_lang_features;
+        let lang_features = &features.declared_lang_features;
         if lang_features.len() == 0 {
             return;
         }
@@ -626,9 +640,7 @@
     }
 }
 
-fn check_incompatible_features(sess: &Session) {
-    let features = sess.features_untracked();
-
+fn check_incompatible_features(sess: &Session, features: &Features) {
     let declared_features = features
         .declared_lang_features
         .iter()
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 59239b4..58ce730 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -150,6 +150,8 @@
 /// and also addresses some specific regressions described in #63896 and #73345.
 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
     if let TokenTree::Token(token, _) = prev {
+        // No space after these tokens, e.g. `x.y`, `$e`
+        // (The carets point to `prev`.)       ^     ^
         if matches!(token.kind, token::Dot | token::Dollar) {
             return false;
         }
@@ -158,10 +160,19 @@
         }
     }
     match tt {
+        // No space before these tokens, e.g. `foo,`, `println!`, `x.y`
+        // (The carets point to `token`.)         ^           ^     ^
+        //
+        // FIXME: having `Not` here works well for macro invocations like
+        // `println!()`, but is bad when `!` means "logical not" or "the never
+        // type", where the lack of space causes ugliness like this:
+        // `Fn() ->!`, `x =! y`, `if! x { f(); }`.
         TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
+        // No space before parentheses if preceded by these tokens, e.g. `foo(...)`
         TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
         }
+        // No space before brackets if preceded by these tokens, e.g. `#[...]`
         TokenTree::Delimited(_, Delimiter::Bracket, _) => {
             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
         }
@@ -476,7 +487,7 @@
                 Some(MacHeader::Path(&item.path)),
                 false,
                 None,
-                delim.to_token(),
+                *delim,
                 tokens,
                 true,
                 span,
@@ -640,7 +651,7 @@
             Some(MacHeader::Keyword(kw)),
             has_bang,
             Some(*ident),
-            macro_def.body.delim.to_token(),
+            macro_def.body.delim,
             &macro_def.body.tokens.clone(),
             true,
             sp,
@@ -1240,7 +1251,7 @@
             Some(MacHeader::Path(&m.path)),
             true,
             None,
-            m.args.delim.to_token(),
+            m.args.delim,
             &m.args.tokens.clone(),
             true,
             m.span(),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 6099201..39741a0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -477,7 +477,7 @@
                 self.word(".");
                 self.print_ident(*ident);
             }
-            ast::ExprKind::Index(expr, index) => {
+            ast::ExprKind::Index(expr, index, _) => {
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.word("[");
                 self.print_expr(index);
@@ -697,15 +697,15 @@
                 write!(template, "{n}").unwrap();
                 if p.format_options != Default::default() || p.format_trait != FormatTrait::Display
                 {
-                    template.push_str(":");
+                    template.push(':');
                 }
                 if let Some(fill) = p.format_options.fill {
                     template.push(fill);
                 }
                 match p.format_options.alignment {
-                    Some(FormatAlignment::Left) => template.push_str("<"),
-                    Some(FormatAlignment::Right) => template.push_str(">"),
-                    Some(FormatAlignment::Center) => template.push_str("^"),
+                    Some(FormatAlignment::Left) => template.push('<'),
+                    Some(FormatAlignment::Right) => template.push('>'),
+                    Some(FormatAlignment::Center) => template.push('^'),
                     None => {}
                 }
                 match p.format_options.sign {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 5c01b7e..d27a44f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -30,10 +30,15 @@
             ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
                 self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
             }
-            ast::ForeignItemKind::Static(ty, mutbl, body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
-            }
+            ast::ForeignItemKind::Static(ty, mutbl, body) => self.print_item_const(
+                ident,
+                Some(*mutbl),
+                &ast::Generics::default(),
+                ty,
+                body.as_deref(),
+                vis,
+                ast::Defaultness::Final,
+            ),
             ast::ForeignItemKind::TyAlias(box ast::TyAlias {
                 defaultness,
                 generics,
@@ -67,6 +72,7 @@
         &mut self,
         ident: Ident,
         mutbl: Option<ast::Mutability>,
+        generics: &ast::Generics,
         ty: &ast::Ty,
         body: Option<&ast::Expr>,
         vis: &ast::Visibility,
@@ -82,6 +88,7 @@
         };
         self.word_space(leading);
         self.print_ident(ident);
+        self.print_generic_params(&generics.params);
         self.word_space(":");
         self.print_type(ty);
         if body.is_some() {
@@ -92,6 +99,7 @@
             self.word_space("=");
             self.print_expr(body);
         }
+        self.print_where_clause(&generics.where_clause);
         self.word(";");
         self.end(); // end the outer cbox
     }
@@ -158,20 +166,21 @@
                 self.word(";");
             }
             ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
-                let def = ast::Defaultness::Final;
                 self.print_item_const(
                     item.ident,
                     Some(*mutbl),
+                    &ast::Generics::default(),
                     ty,
                     body.as_deref(),
                     &item.vis,
-                    def,
+                    ast::Defaultness::Final,
                 );
             }
-            ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
+            ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
                 self.print_item_const(
                     item.ident,
                     None,
+                    generics,
                     ty,
                     expr.as_deref(),
                     &item.vis,
@@ -515,8 +524,16 @@
             ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
                 self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
             }
-            ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
-                self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness);
+            ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
+                self.print_item_const(
+                    ident,
+                    None,
+                    generics,
+                    ty,
+                    expr.as_deref(),
+                    vis,
+                    *defaultness,
+                );
             }
             ast::AssocItemKind::Type(box ast::TyAlias {
                 defaultness,
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 372a588..3592287 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -28,7 +28,7 @@
 }
 
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
-    attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
+    attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
 }
 
 enum AttrError {
@@ -800,18 +800,15 @@
 }
 
 /// Finds the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> {
-    find_deprecation_generic(sess, attrs.iter())
-}
-
-fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)>
-where
-    I: Iterator<Item = &'a Attribute>,
-{
+pub fn find_deprecation(
+    sess: &Session,
+    features: &Features,
+    attrs: &[Attribute],
+) -> Option<(Deprecation, Span)> {
     let mut depr: Option<(Deprecation, Span)> = None;
-    let is_rustc = sess.features_untracked().staged_api;
+    let is_rustc = features.staged_api;
 
-    'outer: for attr in attrs_iter {
+    'outer: for attr in attrs {
         if !attr.has_name(sym::deprecated) {
             continue;
         }
@@ -872,7 +869,7 @@
                                 }
                             }
                             sym::suggestion => {
-                                if !sess.features_untracked().deprecated_suggestion {
+                                if !features.deprecated_suggestion {
                                     sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
                                         span: mi.span,
                                         is_nightly: sess.is_nightly_build().then_some(()),
@@ -890,7 +887,7 @@
                                     meta.span(),
                                     AttrError::UnknownMetaItem(
                                         pprust::path_to_string(&mi.path),
-                                        if sess.features_untracked().deprecated_suggestion {
+                                        if features.deprecated_suggestion {
                                             &["since", "note", "suggestion"]
                                         } else {
                                             &["since", "note"]
@@ -1217,3 +1214,20 @@
         Err("not an unsuffixed integer")
     }
 }
+
+/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names.
+pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
+    let meta = attr.meta()?;
+    let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
+
+    let mut candidates = Vec::new();
+
+    for meta in metas {
+        let NestedMetaItem::Lit(meta_lit) = meta else {
+            return None;
+        };
+        candidates.push(meta_lit.symbol);
+    }
+
+    return Some(candidates);
+}
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index a4e0e77..a2c7e76 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -37,8 +37,8 @@
             desc,
         );
 
-        err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc));
-        err.span_label(span, format!("use of borrowed {}", borrow_desc));
+        err.span_label(borrow_span, format!("{borrow_desc} is borrowed here"));
+        err.span_label(span, format!("use of borrowed {borrow_desc}"));
         err
     }
 
@@ -51,8 +51,7 @@
         old_opt_via: &str,
         old_load_end_span: Option<Span>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let via =
-            |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
+        let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
         let mut err = struct_span_err!(
             self,
             new_loan_span,
@@ -143,9 +142,9 @@
         );
         err.span_label(
             new_loan_span,
-            format!("{} construction occurs here{}", container_name, opt_via),
+            format!("{container_name} construction occurs here{opt_via}"),
         );
-        err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
+        err.span_label(old_loan_span, format!("borrow occurs here{old_opt_via}"));
         if let Some(previous_end_span) = previous_end_span {
             err.span_label(previous_end_span, "borrow ends here");
         }
@@ -173,13 +172,10 @@
             opt_via,
             kind_new,
         );
-        err.span_label(
-            new_loan_span,
-            format!("{}borrow occurs here{}", second_borrow_desc, opt_via),
-        );
+        err.span_label(new_loan_span, format!("{second_borrow_desc}borrow occurs here{opt_via}"));
         err.span_label(
             old_loan_span,
-            format!("{} construction occurs here{}", container_name, old_opt_via),
+            format!("{container_name} construction occurs here{old_opt_via}"),
         );
         if let Some(previous_end_span) = previous_end_span {
             err.span_label(previous_end_span, "borrow from closure ends here");
@@ -199,8 +195,7 @@
         msg_old: &str,
         old_load_end_span: Option<Span>,
     ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
-        let via =
-            |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {})", msg) };
+        let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
         let mut err = struct_span_err!(
             self,
             span,
@@ -216,22 +211,21 @@
 
         if msg_new == "" {
             // If `msg_new` is empty, then this isn't a borrow of a union field.
-            err.span_label(span, format!("{} borrow occurs here", kind_new));
-            err.span_label(old_span, format!("{} borrow occurs here", kind_old));
+            err.span_label(span, format!("{kind_new} borrow occurs here"));
+            err.span_label(old_span, format!("{kind_old} borrow occurs here"));
         } else {
             // If `msg_new` isn't empty, then this a borrow of a union field.
             err.span_label(
                 span,
                 format!(
-                    "{} borrow of {} -- which overlaps with {} -- occurs here",
-                    kind_new, msg_new, msg_old,
+                    "{kind_new} borrow of {msg_new} -- which overlaps with {msg_old} -- occurs here",
                 ),
             );
             err.span_label(old_span, format!("{} borrow occurs here{}", kind_old, via(msg_old)));
         }
 
         if let Some(old_load_end_span) = old_load_end_span {
-            err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
+            err.span_label(old_load_end_span, format!("{kind_old} borrow ends here"));
         }
         err
     }
@@ -250,8 +244,8 @@
             desc,
         );
 
-        err.span_label(borrow_span, format!("{} is borrowed here", desc));
-        err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc));
+        err.span_label(borrow_span, format!("{desc} is borrowed here"));
+        err.span_label(span, format!("{desc} is assigned to here but it was already borrowed"));
         err
     }
 
@@ -330,7 +324,7 @@
         optional_adverb_for_moved: &str,
         moved_path: Option<String>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
+        let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
 
         struct_span_err!(
             self,
@@ -369,8 +363,8 @@
             immutable_place,
             immutable_section,
         );
-        err.span_label(mutate_span, format!("cannot {}", action));
-        err.span_label(immutable_span, format!("value is immutable in {}", immutable_section));
+        err.span_label(mutate_span, format!("cannot {action}"));
+        err.span_label(immutable_span, format!("value is immutable in {immutable_section}"));
         err
     }
 
@@ -428,7 +422,7 @@
 
         err.span_label(
             span,
-            format!("{}s a {} data owned by the current function", return_kind, reference_desc),
+            format!("{return_kind}s a {reference_desc} data owned by the current function"),
         );
 
         err
@@ -449,8 +443,8 @@
             "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
              which is owned by the current {scope}",
         );
-        err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
-            .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));
+        err.span_label(capture_span, format!("{borrowed_path} is borrowed here"))
+            .span_label(closure_span, format!("may outlive borrowed value {borrowed_path}"));
         err
     }
 
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index 743d117..1f64209 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -7,8 +7,8 @@
     Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement,
     StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
-use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
 
 use crate::{
@@ -49,11 +49,11 @@
 }
 
 impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
-    /// We sometimes have `substs` within an rvalue, or within a
+    /// We sometimes have `args` within an rvalue, or within a
     /// call. Make them live at the location where they appear.
-    fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) {
-        self.add_regular_live_constraint(*substs, location);
-        self.super_substs(substs);
+    fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
+        self.add_regular_live_constraint(*args, location);
+        self.super_args(args);
     }
 
     /// We sometimes have `region` within an rvalue, or within a
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index d257145..becfa53 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -30,7 +30,7 @@
 /// will be retrieved.
 #[derive(Debug, Copy, Clone)]
 pub enum ConsumerOptions {
-    /// Retrieve the [`Body`] along with the [`BorrowSet`](super::borrow_set::BorrowSet)
+    /// Retrieve the [`Body`] along with the [`BorrowSet`]
     /// and [`RegionInferenceContext`]. If you would like the body only, use
     /// [`TyCtxt::mir_promoted`].
     ///
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 1064b44..4ac633c 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -2,12 +2,14 @@
 #![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Body, Location, Place};
+use rustc_middle::mir::{
+    self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
+};
 use rustc_middle::ty::RegionVid;
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
 use rustc_mir_dataflow::ResultsVisitable;
-use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
+use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
 use rustc_mir_dataflow::{Analysis, Direction, Results};
 use std::fmt;
 
@@ -334,6 +336,10 @@
 impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     type Idx = BorrowIndex;
 
+    fn domain_size(&self, _: &mir::Body<'tcx>) -> usize {
+        self.borrow_set.len()
+    }
+
     fn before_statement_effect(
         &mut self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -360,7 +366,7 @@
                         return;
                     }
                     let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| {
-                        panic!("could not find BorrowIndex for location {:?}", location);
+                        panic!("could not find BorrowIndex for location {location:?}");
                     });
 
                     trans.gen(index);
@@ -400,12 +406,12 @@
         self.kill_loans_out_of_scope_at_location(trans, location);
     }
 
-    fn terminator_effect(
+    fn terminator_effect<'mir>(
         &mut self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
+        trans: &mut Self::Domain,
+        terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
-    ) {
+    ) -> TerminatorEdges<'mir, 'tcx> {
         if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind {
             for op in operands {
                 if let mir::InlineAsmOperand::Out { place: Some(place), .. }
@@ -415,6 +421,7 @@
                 }
             }
         }
+        terminator.edges()
     }
 
     fn call_return_effect(
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index c8c8b72..fe4a45b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -363,21 +363,12 @@
             }
         }
         let hir = self.infcx.tcx.hir();
-        if let Some(hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Fn(_, _, body_id),
-            ..
-        })) = hir.find(self.mir_hir_id())
-            && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
-        {
+        if let Some(body_id) = hir.maybe_body_owned_by(self.mir_def_id()) {
+            let expr = hir.body(body_id).value;
             let place = &self.move_data.move_paths[mpi].place;
-            let span = place.as_local()
-                .map(|local| self.body.local_decls[local].source_info.span);
-            let mut finder = ExpressionFinder {
-                expr_span: move_span,
-                expr: None,
-                pat: None,
-                parent_pat: None,
-            };
+            let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span);
+            let mut finder =
+                ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None };
             finder.visit_expr(expr);
             if let Some(span) = span && let Some(expr) = finder.expr {
                 for (_, expr) in hir.parent_iter(expr.hir_id) {
@@ -461,7 +452,7 @@
                     } = move_spans {
                         // We already suggest cloning for these cases in `explain_captures`.
                     } else {
-                        self.suggest_cloning(err, ty, move_span);
+                        self.suggest_cloning(err, ty, expr, move_span);
                     }
                 }
             }
@@ -662,7 +653,7 @@
             err.span_suggestion_verbose(
                 sugg_span.shrink_to_hi(),
                 "consider assigning a value",
-                format!(" = {}", assign_value),
+                format!(" = {assign_value}"),
                 Applicability::MaybeIncorrect,
             );
         }
@@ -702,11 +693,11 @@
                 .iter()
                 .copied()
                 .find_map(find_fn_kind_from_did),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
+            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx
                 .explicit_item_bounds(def_id)
-                .subst_iter_copied(tcx, substs)
+                .iter_instantiated_copied(tcx, args)
                 .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
-            ty::Closure(_, substs) => match substs.as_closure().kind() {
+            ty::Closure(_, args) => match args.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
                 _ => None,
@@ -714,7 +705,9 @@
             _ => None,
         };
 
-        let Some(borrow_level) = borrow_level else { return false; };
+        let Some(borrow_level) = borrow_level else {
+            return false;
+        };
         let sugg = move_sites
             .iter()
             .map(|move_site| {
@@ -734,9 +727,21 @@
         true
     }
 
-    fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
+    fn suggest_cloning(
+        &self,
+        err: &mut Diagnostic,
+        ty: Ty<'tcx>,
+        expr: &hir::Expr<'_>,
+        span: Span,
+    ) {
         let tcx = self.infcx.tcx;
         // Try to find predicates on *generic params* that would allow copying `ty`
+        let suggestion =
+            if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
+                format!(": {symbol}.clone()")
+            } else {
+                ".clone()".to_owned()
+            };
         if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
             && self.infcx
                 .type_implements_trait(
@@ -746,10 +751,20 @@
                 )
                 .must_apply_modulo_regions()
         {
+            let msg = if let ty::Adt(def, _) = ty.kind()
+                && [
+                    tcx.get_diagnostic_item(sym::Arc),
+                    tcx.get_diagnostic_item(sym::Rc),
+                ].contains(&Some(def.did()))
+            {
+                "clone the value to increment its reference count"
+            } else {
+                "consider cloning the value if the performance cost is acceptable"
+            };
             err.span_suggestion_verbose(
                 span.shrink_to_hi(),
-                "consider cloning the value if the performance cost is acceptable",
-                ".clone()",
+                msg,
+                suggestion,
                 Applicability::MachineApplicable,
             );
         }
@@ -763,7 +778,9 @@
             .typeck_root_def_id(self.mir_def_id().to_def_id())
             .as_local()
             .and_then(|def_id| tcx.hir().get_generics(def_id))
-        else { return; };
+        else {
+            return;
+        };
         // Try to find predicates on *generic params* that would allow copying `ty`
         let ocx = ObligationCtxt::new(&self.infcx);
         let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
@@ -1155,8 +1172,7 @@
 
         if union_type_name != "" {
             err.note(format!(
-                "{} is a field of the union `{}`, so it overlaps the field {}",
-                msg_place, union_type_name, msg_borrow,
+                "{msg_place} is a field of the union `{union_type_name}`, so it overlaps the field {msg_borrow}",
             ));
         }
 
@@ -1220,18 +1236,20 @@
             return;
         };
         let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
-        let Some((inner_call_loc, inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
-            let Either::Right(term) = self.body.stmt_at(loc) else {
-                debug!("{:?} is a statement, so it can't be a call", loc);
-                return None;
-            };
-            let TerminatorKind::Call { args, .. } = &term.kind else {
-                debug!("not a call: {:?}", term);
-                return None;
-            };
-            debug!("checking call args for uses of inner_param: {:?}", args);
-            args.contains(&Operand::Move(inner_param)).then_some((loc, term))
-        }) else {
+        let Some((inner_call_loc, inner_call_term)) =
+            inner_param_uses.into_iter().find_map(|loc| {
+                let Either::Right(term) = self.body.stmt_at(loc) else {
+                    debug!("{:?} is a statement, so it can't be a call", loc);
+                    return None;
+                };
+                let TerminatorKind::Call { args, .. } = &term.kind else {
+                    debug!("not a call: {:?}", term);
+                    return None;
+                };
+                debug!("checking call args for uses of inner_param: {:?}", args);
+                args.contains(&Operand::Move(inner_param)).then_some((loc, term))
+            })
+        else {
             debug!("no uses of inner_param found as a by-move call arg");
             return;
         };
@@ -1344,8 +1362,7 @@
                 let Some(trait_did) = tcx.trait_of_item(def_id) &&
                 tcx.is_diagnostic_item(sym::Iterator, trait_did) {
                     err.note(format!(
-                        "a for loop advances the iterator for you, the result is stored in `{}`.",
-                        loop_bind
+                        "a for loop advances the iterator for you, the result is stored in `{loop_bind}`."
                     ));
                     err.help("if you want to call `next` on a iterator within the loop, consider using `while let`.");
         }
@@ -1442,21 +1459,24 @@
         }
 
         // Get closure's arguments
-        let ty::Closure(_, substs) = typeck_results.expr_ty(closure_expr).kind() else { /* hir::Closure can be a generator too */ return };
-        let sig = substs.as_closure().sig();
+        let ty::Closure(_, args) = typeck_results.expr_ty(closure_expr).kind() else {
+            /* hir::Closure can be a generator too */
+            return;
+        };
+        let sig = args.as_closure().sig();
         let tupled_params =
             tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b));
         let ty::Tuple(params) = tupled_params.kind() else { return };
 
         // Find the first argument with a matching type, get its name
-        let Some((_, this_name)) = params
-            .iter()
-            .zip(hir.body_param_names(closure.body))
-            .find(|(param_ty, name)|{
+        let Some((_, this_name)) =
+            params.iter().zip(hir.body_param_names(closure.body)).find(|(param_ty, name)| {
                 // FIXME: also support deref for stuff like `Rc` arguments
                 param_ty.peel_refs() == local_ty && name != &Ident::empty()
             })
-            else { return };
+        else {
+            return;
+        };
 
         let spans;
         if let Some((_path_expr, qpath)) = finder.error_path
@@ -1813,7 +1833,7 @@
                     },
                     ConstraintCategory::CallArgument(None),
                     var_or_use_span,
-                    &format!("`{}`", name),
+                    &format!("`{name}`"),
                     "block",
                 ),
             (
@@ -1835,7 +1855,7 @@
                     region_name,
                     category,
                     span,
-                    &format!("`{}`", name),
+                    &format!("`{name}`"),
                     "function",
                 ),
             (
@@ -1909,14 +1929,14 @@
             }
         }
 
-        let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
+        let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`"));
 
         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
             let region_name = annotation.emit(self, &mut err);
 
             err.span_label(
                 borrow_span,
-                format!("`{}` would have to be valid for `{}`...", name, region_name),
+                format!("`{name}` would have to be valid for `{region_name}`..."),
             );
 
             err.span_label(
@@ -1927,7 +1947,7 @@
                     self.infcx
                         .tcx
                         .opt_item_name(self.mir_def_id().to_def_id())
-                        .map(|name| format!("function `{}`", name))
+                        .map(|name| format!("function `{name}`"))
                         .unwrap_or_else(|| {
                             match &self.infcx.tcx.def_kind(self.mir_def_id()) {
                                 DefKind::Closure => "enclosing closure",
@@ -1962,7 +1982,7 @@
             }
         } else {
             err.span_label(borrow_span, "borrowed value does not live long enough");
-            err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
+            err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
 
             borrow_spans.args_subdiag(&mut err, |args_span| {
                 crate::session_diagnostics::CaptureArgLabel::Capture {
@@ -2006,22 +2026,17 @@
         let mut err = self.cannot_borrow_across_destructor(borrow_span);
 
         let what_was_dropped = match self.describe_place(place.as_ref()) {
-            Some(name) => format!("`{}`", name),
+            Some(name) => format!("`{name}`"),
             None => String::from("temporary value"),
         };
 
         let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
             Some(borrowed) => format!(
-                "here, drop of {D} needs exclusive access to `{B}`, \
-                 because the type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty,
-                B = borrowed
+                "here, drop of {what_was_dropped} needs exclusive access to `{borrowed}`, \
+                 because the type `{dropped_ty}` implements the `Drop` trait"
             ),
             None => format!(
-                "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
-                D = what_was_dropped,
-                T = dropped_ty
+                "here is drop of {what_was_dropped}; whose type `{dropped_ty}` implements the `Drop` trait"
             ),
         };
         err.span_label(drop_span, label);
@@ -2128,13 +2143,14 @@
                         self.current -= 1;
                     }
                     fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
-                        if self.span == expr.span {
+                        if self.span == expr.span.source_callsite() {
                             self.found = self.current;
                         }
                         walk_expr(self, expr);
                     }
                 }
                 let source_info = self.body.source_info(location);
+                let proper_span = proper_span.source_callsite();
                 if let Some(scope) = self.body.source_scopes.get(source_info.scope)
                     && let ClearCrossCrate::Set(scope_data) = &scope.local_data
                     && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
@@ -2233,10 +2249,7 @@
             } else {
                 "local data "
             };
-            (
-                format!("{}`{}`", local_kind, place_desc),
-                format!("`{}` is borrowed here", place_desc),
-            )
+            (format!("{local_kind}`{place_desc}`"), format!("`{place_desc}` is borrowed here"))
         } else {
             let root_place =
                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
@@ -2338,9 +2351,8 @@
         err.span_suggestion_verbose(
             sugg_span,
             format!(
-                "to force the {} to take ownership of {} (and any \
-                 other referenced variables), use the `move` keyword",
-                kind, captured_var
+                "to force the {kind} to take ownership of {captured_var} (and any \
+                 other referenced variables), use the `move` keyword"
             ),
             suggestion,
             Applicability::MachineApplicable,
@@ -2348,7 +2360,7 @@
 
         match category {
             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
-                let