Copy zerocopy and zerocopy-derive to extra_versions.

This change won't build on its own because of duplicate build rules.

Fixing cargo_embargo.json will be a separate change so that reviewers can see what
exactly is different. Both changes will be submitted together.

Bug: 372549215
Test: treehugger
Change-Id: I1854590f4ddb41e742e3ee09295d05ed1ac66e6e
diff --git a/extra_versions/crates/zerocopy-derive/.cargo-checksum.json b/extra_versions/crates/zerocopy-derive/.cargo-checksum.json
new file mode 100644
index 0000000..fbb75d7
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"c40aeff1053c2c2d5fb16d9e56ce6ac385d04a49e10a1a61ef58bfdcee25a140","LICENSE-APACHE":"9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3","LICENSE-BSD":"83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32","LICENSE-MIT":"1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df","src/ext.rs":"d741f6132fca552676b132a38b6431362054aec0c86dcf1c281bca51d5decad2","src/lib.rs":"d9f83e05ed8444076a6df846aa609dcbbea3931a1f6da3d1f37611163f8ff903","src/repr.rs":"780f547b9d51794ec35ea9359a2c55cd40cf1d84f6e1f4080034ff337df953c1","tests/enum_as_bytes.rs":"2e11daa46c6b922d748321e9a47c3b355e2a9e3b48af95a699c39186b7783711","tests/enum_from_zeroes.rs":"32ca3d0dc9085ef8eb9597b5e057ff0b3a0e92b6da44fac3326b2a124010ba4b","tests/enum_known_layout.rs":"7bc4979b3f9cadc4784afd821ea1c0670fe987a842627f9bb4406b248c5c6ce4","tests/enum_unaligned.rs":"0c42281098047c6a106c2eae2ee792b893b4f295e8147cf56eaf826888be5fbf","tests/hygiene.rs":"24f6fb3e4f1aa313753d3f16d9285105b836392f9d68de77ea436a9b24443102","tests/paths_and_modules.rs":"4218b6ac5d1aeb2d3b199af5f64eea45ab1117fc135e9d30588ff761e98b0f10","tests/priv_in_pub.rs":"57ff0106151dc34f2e14be90ca73c1c7e6791215683b28fc68abd2deed90fedb","tests/struct_as_bytes.rs":"334053105b4341376e11a895ceb534b1f0961100f7d04ece17745fbf7d58e0ca","tests/struct_from_bytes.rs":"90e4d0d7cd9b72f3338edff937f195614fca52b6d937cfbba5c2bc763ebc1e60","tests/struct_from_zeroes.rs":"52d6965cd7571926683e85b5b13e09a25144ad0615c7c73ac3a0abf99fa33cb8","tests/struct_known_layout.rs":"1d54c62a9f4682a1ae4174cee9c73c5f0986623f7bbb069c1bed78b82be36989","tests/struct_unaligned.rs":"a5d3377dda1ba884ec4b70ca043f599eccba3b2258de16c58a72c43633507e2e","tests/trybuild.rs":"0954299d2c50d06259a628fa828131e9f0e8953dfcc2cf0d52d6d9ff40c969d5","tests/ui-msrv/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-msrv/derive_transparent.stderr":"b8a66f15647fa8ef3ab5ab371710f36943b42af8f3d2d088509c05f029ad7b8d","tests/ui-msrv/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-msrv/enum.stderr":"321e41c161804d3918fd15214845862c5ca346581e88cf0260073e3c6203cc21","tests/ui-msrv/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-msrv/enum_from_bytes_u8_too_few.stderr":"a5ab2757166ef9dfa51a09d3dbddd5e9e2b1a46bd3d4b8d175b33a90747878d7","tests/ui-msrv/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-msrv/late_compile_pass.stderr":"a8598656086bfc855c7c69131e08b3ac0eac22c5a731346ab4fb5d06dc0dd8e6","tests/ui-msrv/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-msrv/mid_compile_pass.stderr":"d2d8d441c7642ca266a4250e8b6a4a9aa693cfc2ec48f679600e392e7b6c6273","tests/ui-msrv/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-msrv/struct.stderr":"eb245197d856850ea4e9c6ec58fae60058dee5f7fb7ca68b113e4c9cd7826b34","tests/ui-msrv/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-msrv/union.stderr":"a75b425e50af3759dfe4d2bf832b4cb650ddbaf6b5c8853aa904be98685f1e53","tests/ui-nightly/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-nightly/derive_transparent.stderr":"9a3f6eae91f2f4f2c6ed8d517f98e2f427ec75ba23ad27c86cbb4c587dcd3e74","tests/ui-nightly/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-nightly/enum.stderr":"9b4d965632beb995022209f0f4ca5d875725f33149916a963402b1901e1dbf14","tests/ui-nightly/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-nightly/enum_from_bytes_u8_too_few.stderr":"28a493e1057279ea8e20df49ff0c02dfa132027a86bb6f5fe50e250c14e62572","tests/ui-nightly/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-nightly/late_compile_pass.stderr":"46d7db9d292eb56be04783f01e9b54d335003ccec48689126654a36b97cc9d92","tests/ui-nightly/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-nightly/mid_compile_pass.stderr":"359f468b1f6313f5a7d5533fa5fe09d80a759e8adf523c9a8edff8b636b5e4b3","tests/ui-nightly/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-nightly/struct.stderr":"abc60481cd303a84507d06d6ed351f58598ee1e57502b37711534930fc611ea5","tests/ui-nightly/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-nightly/union.stderr":"bbaa6c1ac4df2e263fb884b6d356a3e366e68a0cdc7d8e32489eabac594b76a5","tests/ui-stable/derive_transparent.rs":"9f15bf0bf22c8e47c3d645f99239462eae6a875bd469510ad41838d9ae4ed1f8","tests/ui-stable/derive_transparent.stderr":"0698083580c991aeeeb7b8a9f8cac803abe711b6ebf2917a95a21de46ea9ff6c","tests/ui-stable/enum.rs":"7eb4f7f912f91c9a040536882b398ac4f07153fd8dbcc49a30603c6eb8107899","tests/ui-stable/enum.stderr":"3d2f2fa112f70f7c18e6aa3400ed5f28ff39b9241de4fdecf7e786bfe85ceadc","tests/ui-stable/enum_from_bytes_u8_too_few.rs":"afbec6f24a4bfca472f2929abc5125d8f5b305a0a1b472a1215ad7739ed63100","tests/ui-stable/enum_from_bytes_u8_too_few.stderr":"b3edb381f968f6f2ad9ab4810132df5962b0650460e07f77af818ababf124fe7","tests/ui-stable/late_compile_pass.rs":"244f7dcc9a821a400fe3c24323cf8ffe89aa28454527a85b492fc5afd5cae205","tests/ui-stable/late_compile_pass.stderr":"bd96e3da0befae5f09458e94c2e03066cf4c010ca6733ce541f8d847a5a03f42","tests/ui-stable/mid_compile_pass.rs":"b80b01bfd383c537173f7d630ec2789a2af3e01bc6d53c807fdcf271b235d0c9","tests/ui-stable/mid_compile_pass.stderr":"31eff0a802e3e5081337e30260d984c68358211ef0ba7a71fcdd409bf3740023","tests/ui-stable/struct.rs":"882b8f0a84ac772aaec5a4f786a5216ad37a269a6d9f1f836f1b27cbe861743c","tests/ui-stable/struct.stderr":"d7444f398e915d40b0cf4ab1d2600468ce1948c4bb0ac28b9f30d1c88404f90d","tests/ui-stable/union.rs":"0661431d493e5690653ba0ed076fba14ab03fff81471d572369269aa58bde5a0","tests/ui-stable/union.stderr":"a238e0295fd6b32e918fe820410322941c10662ff21f31af704c380c301fc165","tests/union_as_bytes.rs":"57e69981ed7bb8eebbb2ea2be160532074e32aa4cec6543e9e3af0f5e3767fd8","tests/union_from_bytes.rs":"7da559bbb70fb2dbbb7422ad3099d8c2504d5815bc1e87173ffa758b929382b2","tests/union_from_zeroes.rs":"448d21026955403e1f09c69e19c3542a454456aab1c13d32dad8c612b8cbc7f8","tests/union_known_layout.rs":"a94be098de0a2565d1cf3e9631b36c250ddae1c3490f18e9d8a7b6f70274ec00","tests/union_unaligned.rs":"c8a0458226645063805b9653c2148048e7b93b273b93e7959a969f15e167fa57","tests/util.rs":"8d0cfb435e4b154a3702511f3d10331d6b01bcd90f0d70d4a094778813e9e387"},"package":"fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"}
\ No newline at end of file
diff --git a/extra_versions/crates/zerocopy-derive/Android.bp b/extra_versions/crates/zerocopy-derive/Android.bp
new file mode 100644
index 0000000..b362086
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/Android.bp
@@ -0,0 +1,36 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+    default_applicable_licenses: ["external_rust_crates_zerocopy-derive_license"],
+    default_team: "trendy_team_android_rust",
+}
+
+license {
+    name: "external_rust_crates_zerocopy-derive_license",
+    visibility: [":__subpackages__"],
+    license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+    license_text: ["LICENSE"],
+}
+
+rust_proc_macro {
+    name: "libzerocopy_derive",
+    crate_name: "zerocopy_derive",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.7.35",
+    crate_root: "src/lib.rs",
+    edition: "2018",
+    rustlibs: [
+        "libproc_macro2",
+        "libquote",
+        "libsyn",
+    ],
+    product_available: true,
+    vendor_available: true,
+}
+
+dirgroup {
+    name: "trusty_dirgroup_external_rust_crates_zerocopy-derive",
+    visibility: ["//trusty/vendor/google/aosp/scripts"],
+    dirs: ["."],
+}
diff --git a/extra_versions/crates/zerocopy-derive/Cargo.toml b/extra_versions/crates/zerocopy-derive/Cargo.toml
new file mode 100644
index 0000000..70758ac
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/Cargo.toml
@@ -0,0 +1,43 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "zerocopy-derive"
+version = "0.7.35"
+authors = ["Joshua Liebow-Feeser <joshlf@google.com>"]
+exclude = [
+    ".*",
+    "tests/enum_from_bytes.rs",
+    "tests/ui-nightly/enum_from_bytes_u16_too_few.rs.disabled",
+]
+description = "Custom derive for traits from the zerocopy crate"
+license = "BSD-2-Clause OR Apache-2.0 OR MIT"
+repository = "https://github.com/google/zerocopy"
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1.0.1"
+
+[dependencies.quote]
+version = "1.0.10"
+
+[dependencies.syn]
+version = "2.0.31"
+
+[dev-dependencies.static_assertions]
+version = "1.1"
+
+[dev-dependencies.trybuild]
+version = "=1.0.85"
+features = ["diff"]
diff --git a/extra_versions/crates/zerocopy-derive/LICENSE b/extra_versions/crates/zerocopy-derive/LICENSE
new file mode 100644
index 0000000..7ed244f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2019 The Fuchsia Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy-derive/LICENSE-APACHE b/extra_versions/crates/zerocopy-derive/LICENSE-APACHE
new file mode 100644
index 0000000..2dc22c1
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/LICENSE-APACHE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2023 The Fuchsia Authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/extra_versions/crates/zerocopy-derive/LICENSE-BSD b/extra_versions/crates/zerocopy-derive/LICENSE-BSD
new file mode 100644
index 0000000..7ed244f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/LICENSE-BSD
@@ -0,0 +1,24 @@
+Copyright 2019 The Fuchsia Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy-derive/LICENSE-MIT b/extra_versions/crates/zerocopy-derive/LICENSE-MIT
new file mode 100644
index 0000000..26e1521
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2023 The Fuchsia Authors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/extra_versions/crates/zerocopy-derive/METADATA b/extra_versions/crates/zerocopy-derive/METADATA
new file mode 100644
index 0000000..6708a1f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/METADATA
@@ -0,0 +1,17 @@
+name: "zerocopy-derive"
+description: "Custom derive for traits from the zerocopy crate"
+third_party {
+  version: "0.7.35"
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2024
+    month: 9
+    day: 5
+  }
+  homepage: "https://crates.io/crates/zerocopy-derive"
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/zerocopy-derive/zerocopy-derive-0.7.35.crate"
+    version: "0.7.35"
+  }
+}
diff --git a/extra_versions/crates/zerocopy-derive/MODULE_LICENSE_BSD_LIKE b/extra_versions/crates/zerocopy-derive/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/MODULE_LICENSE_BSD_LIKE
diff --git a/extra_versions/crates/zerocopy-derive/TEST_MAPPING b/extra_versions/crates/zerocopy-derive/TEST_MAPPING
new file mode 100644
index 0000000..d0d297a
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "imports": [
+    {
+      "path": "external/rust/android-crates-io/crates/virtio-drivers"
+    },
+    {
+      "path": "external/rust/crates/zerocopy"
+    }
+  ]
+}
diff --git a/extra_versions/crates/zerocopy-derive/cargo_embargo.json b/extra_versions/crates/zerocopy-derive/cargo_embargo.json
new file mode 100644
index 0000000..1dc3922
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/cargo_embargo.json
@@ -0,0 +1,4 @@
+{
+  "run_cargo": false,
+  "generate_rulesmk": true
+}
diff --git a/extra_versions/crates/zerocopy-derive/patches/LICENSE.patch b/extra_versions/crates/zerocopy-derive/patches/LICENSE.patch
new file mode 100644
index 0000000..150d4e0
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/patches/LICENSE.patch
@@ -0,0 +1,30 @@
+diff --git b/LICENSE a/LICENSE
+new file mode 100644
+index 0000000..7ed244f
+--- /dev/null
++++ a/LICENSE
+@@ -0,0 +1,24 @@
++Copyright 2019 The Fuchsia Authors.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are
++met:
++
++   * Redistributions of source code must retain the above copyright
++notice, this list of conditions and the following disclaimer.
++   * Redistributions in binary form must reproduce the above
++copyright notice, this list of conditions and the following disclaimer
++in the documentation and/or other materials provided with the
++distribution.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy-derive/rules.mk b/extra_versions/crates/zerocopy-derive/rules.mk
new file mode 100644
index 0000000..73a9f90
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/rules.mk
@@ -0,0 +1,17 @@
+# This file is generated by cargo_embargo.
+# Do not modify this file after the LOCAL_DIR line
+# because the changes will be overridden on upgrade.
+# Content before the first line starting with LOCAL_DIR is preserved.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+MODULE_CRATE_NAME := zerocopy_derive
+MODULE_RUST_CRATE_TYPES := proc-macro
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+MODULE_RUST_EDITION := 2018
+MODULE_LIBRARY_DEPS := \
+	$(call FIND_CRATE,proc-macro2) \
+	$(call FIND_CRATE,quote) \
+	$(call FIND_CRATE,syn)
+
+include make/library.mk
diff --git a/extra_versions/crates/zerocopy-derive/src/ext.rs b/extra_versions/crates/zerocopy-derive/src/ext.rs
new file mode 100644
index 0000000..87cf838
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/src/ext.rs
@@ -0,0 +1,53 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use syn::{Data, DataEnum, DataStruct, DataUnion, Type};
+
+pub trait DataExt {
+    /// Extract the types of all fields. For enums, extract the types of fields
+    /// from each variant.
+    fn field_types(&self) -> Vec<&Type>;
+}
+
+impl DataExt for Data {
+    fn field_types(&self) -> Vec<&Type> {
+        match self {
+            Data::Struct(strc) => strc.field_types(),
+            Data::Enum(enm) => enm.field_types(),
+            Data::Union(un) => un.field_types(),
+        }
+    }
+}
+
+impl DataExt for DataStruct {
+    fn field_types(&self) -> Vec<&Type> {
+        self.fields.iter().map(|f| &f.ty).collect()
+    }
+}
+
+impl DataExt for DataEnum {
+    fn field_types(&self) -> Vec<&Type> {
+        self.variants.iter().flat_map(|var| &var.fields).map(|f| &f.ty).collect()
+    }
+}
+
+impl DataExt for DataUnion {
+    fn field_types(&self) -> Vec<&Type> {
+        self.fields.named.iter().map(|f| &f.ty).collect()
+    }
+}
+
+pub trait EnumExt {
+    fn is_c_like(&self) -> bool;
+}
+
+impl EnumExt for DataEnum {
+    fn is_c_like(&self) -> bool {
+        self.field_types().is_empty()
+    }
+}
diff --git a/extra_versions/crates/zerocopy-derive/src/lib.rs b/extra_versions/crates/zerocopy-derive/src/lib.rs
new file mode 100644
index 0000000..1767310
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/src/lib.rs
@@ -0,0 +1,887 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Derive macros for [zerocopy]'s traits.
+//!
+//! [zerocopy]: https://docs.rs/zerocopy
+
+// Sometimes we want to use lints which were added after our MSRV.
+// `unknown_lints` is `warn` by default and we deny warnings in CI, so without
+// this attribute, any unknown lint would cause a CI failure when testing with
+// our MSRV.
+#![allow(unknown_lints)]
+#![deny(renamed_and_removed_lints)]
+#![deny(clippy::all, clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks)]
+#![deny(
+    rustdoc::bare_urls,
+    rustdoc::broken_intra_doc_links,
+    rustdoc::invalid_codeblock_attributes,
+    rustdoc::invalid_html_tags,
+    rustdoc::invalid_rust_codeblocks,
+    rustdoc::missing_crate_level_docs,
+    rustdoc::private_intra_doc_links
+)]
+#![recursion_limit = "128"]
+
+mod ext;
+mod repr;
+
+use {
+    proc_macro2::Span,
+    quote::quote,
+    syn::{
+        parse_quote, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error, Expr, ExprLit,
+        GenericParam, Ident, Lit,
+    },
+};
+
+use {crate::ext::*, crate::repr::*};
+
+// Unwraps a `Result<_, Vec<Error>>`, converting any `Err` value into a
+// `TokenStream` and returning it.
+macro_rules! try_or_print {
+    ($e:expr) => {
+        match $e {
+            Ok(x) => x,
+            Err(errors) => return print_all_errors(errors).into(),
+        }
+    };
+}
+
+// TODO(https://github.com/rust-lang/rust/issues/54140): Some errors could be
+// made better if we could add multiple lines of error output like this:
+//
+// error: unsupported representation
+//   --> enum.rs:28:8
+//    |
+// 28 | #[repr(transparent)]
+//    |
+// help: required by the derive of FromBytes
+//
+// Instead, we have more verbose error messages like "unsupported representation
+// for deriving FromZeroes, FromBytes, AsBytes, or Unaligned on an enum"
+//
+// This will probably require Span::error
+// (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error),
+// which is currently unstable. Revisit this once it's stable.
+
+#[proc_macro_derive(KnownLayout)]
+pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(ts as DeriveInput);
+
+    let is_repr_c_struct = match &ast.data {
+        Data::Struct(..) => {
+            let reprs = try_or_print!(repr::reprs::<Repr>(&ast.attrs));
+            if reprs.iter().any(|(_meta, repr)| repr == &Repr::C) {
+                Some(reprs)
+            } else {
+                None
+            }
+        }
+        Data::Enum(..) | Data::Union(..) => None,
+    };
+
+    let fields = ast.data.field_types();
+
+    let (require_self_sized, extras) = if let (
+        Some(reprs),
+        Some((trailing_field, leading_fields)),
+    ) = (is_repr_c_struct, fields.split_last())
+    {
+        let repr_align = reprs
+            .iter()
+            .find_map(
+                |(_meta, repr)| {
+                    if let Repr::Align(repr_align) = repr {
+                        Some(repr_align)
+                    } else {
+                        None
+                    }
+                },
+            )
+            .map(|repr_align| quote!(NonZeroUsize::new(#repr_align as usize)))
+            .unwrap_or(quote!(None));
+
+        let repr_packed = reprs
+            .iter()
+            .find_map(|(_meta, repr)| match repr {
+                Repr::Packed => Some(1),
+                Repr::PackedN(repr_packed) => Some(*repr_packed),
+                _ => None,
+            })
+            .map(|repr_packed| quote!(NonZeroUsize::new(#repr_packed as usize)))
+            .unwrap_or(quote!(None));
+
+        (
+            false,
+            quote!(
+                // SAFETY: `LAYOUT` accurately describes the layout of `Self`.
+                // The layout of `Self` is reflected using a sequence of
+                // invocations of `DstLayout::{new_zst,extend,pad_to_align}`.
+                // The documentation of these items vows that invocations in
+                // this manner will acurately describe a type, so long as:
+                //
+                //  - that type is `repr(C)`,
+                //  - its fields are enumerated in the order they appear,
+                //  - the presence of `repr_align` and `repr_packed` are correctly accounted for.
+                //
+                // We respect all three of these preconditions here. This
+                // expansion is only used if `is_repr_c_struct`, we enumerate
+                // the fields in order, and we extract the values of `align(N)`
+                // and `packed(N)`.
+                const LAYOUT: ::zerocopy::DstLayout = {
+                    use ::zerocopy::macro_util::core_reexport::num::NonZeroUsize;
+                    use ::zerocopy::{DstLayout, KnownLayout};
+
+                    let repr_align = #repr_align;
+                    let repr_packed = #repr_packed;
+
+                    DstLayout::new_zst(repr_align)
+                        #(.extend(DstLayout::for_type::<#leading_fields>(), repr_packed))*
+                        .extend(<#trailing_field as KnownLayout>::LAYOUT, repr_packed)
+                        .pad_to_align()
+                };
+
+                // SAFETY:
+                // - The recursive call to `raw_from_ptr_len` preserves both address and provenance.
+                // - The `as` cast preserves both address and provenance.
+                // - `NonNull::new_unchecked` preserves both address and provenance.
+                #[inline(always)]
+                fn raw_from_ptr_len(
+                    bytes: ::zerocopy::macro_util::core_reexport::ptr::NonNull<u8>,
+                    elems: usize,
+                ) -> ::zerocopy::macro_util::core_reexport::ptr::NonNull<Self> {
+                    use ::zerocopy::{KnownLayout};
+                    let trailing = <#trailing_field as KnownLayout>::raw_from_ptr_len(bytes, elems);
+                    let slf = trailing.as_ptr() as *mut Self;
+                    // SAFETY: Constructed from `trailing`, which is non-null.
+                    unsafe { ::zerocopy::macro_util::core_reexport::ptr::NonNull::new_unchecked(slf) }
+                }
+            ),
+        )
+    } else {
+        // For enums, unions, and non-`repr(C)` structs, we require that
+        // `Self` is sized, and as a result don't need to reason about the
+        // internals of the type.
+        (
+            true,
+            quote!(
+                // SAFETY: `LAYOUT` is guaranteed to accurately describe the
+                // layout of `Self`, because that is the documented safety
+                // contract of `DstLayout::for_type`.
+                const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_type::<Self>();
+
+                // SAFETY: `.cast` preserves address and provenance.
+                //
+                // TODO(#429): Add documentation to `.cast` that promises that
+                // it preserves provenance.
+                #[inline(always)]
+                fn raw_from_ptr_len(
+                    bytes: ::zerocopy::macro_util::core_reexport::ptr::NonNull<u8>,
+                    _elems: usize,
+                ) -> ::zerocopy::macro_util::core_reexport::ptr::NonNull<Self> {
+                    bytes.cast::<Self>()
+                }
+            ),
+        )
+    };
+
+    match &ast.data {
+        Data::Struct(strct) => {
+            let require_trait_bound_on_field_types = if require_self_sized {
+                RequireBoundedFields::No
+            } else {
+                RequireBoundedFields::Trailing
+            };
+
+            // A bound on the trailing field is required, since structs are
+            // unsized if their trailing field is unsized. Reflecting the layout
+            // of an usized trailing field requires that the field is
+            // `KnownLayout`.
+            impl_block(
+                &ast,
+                strct,
+                Trait::KnownLayout,
+                require_trait_bound_on_field_types,
+                require_self_sized,
+                None,
+                Some(extras),
+            )
+        }
+        Data::Enum(enm) => {
+            // A bound on the trailing field is not required, since enums cannot
+            // currently be unsized.
+            impl_block(
+                &ast,
+                enm,
+                Trait::KnownLayout,
+                RequireBoundedFields::No,
+                true,
+                None,
+                Some(extras),
+            )
+        }
+        Data::Union(unn) => {
+            // A bound on the trailing field is not required, since unions
+            // cannot currently be unsized.
+            impl_block(
+                &ast,
+                unn,
+                Trait::KnownLayout,
+                RequireBoundedFields::No,
+                true,
+                None,
+                Some(extras),
+            )
+        }
+    }
+    .into()
+}
+
+#[proc_macro_derive(FromZeroes)]
+pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(ts as DeriveInput);
+    match &ast.data {
+        Data::Struct(strct) => derive_from_zeroes_struct(&ast, strct),
+        Data::Enum(enm) => derive_from_zeroes_enum(&ast, enm),
+        Data::Union(unn) => derive_from_zeroes_union(&ast, unn),
+    }
+    .into()
+}
+
+#[proc_macro_derive(FromBytes)]
+pub fn derive_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(ts as DeriveInput);
+    match &ast.data {
+        Data::Struct(strct) => derive_from_bytes_struct(&ast, strct),
+        Data::Enum(enm) => derive_from_bytes_enum(&ast, enm),
+        Data::Union(unn) => derive_from_bytes_union(&ast, unn),
+    }
+    .into()
+}
+
+#[proc_macro_derive(AsBytes)]
+pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(ts as DeriveInput);
+    match &ast.data {
+        Data::Struct(strct) => derive_as_bytes_struct(&ast, strct),
+        Data::Enum(enm) => derive_as_bytes_enum(&ast, enm),
+        Data::Union(unn) => derive_as_bytes_union(&ast, unn),
+    }
+    .into()
+}
+
+#[proc_macro_derive(Unaligned)]
+pub fn derive_unaligned(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let ast = syn::parse_macro_input!(ts as DeriveInput);
+    match &ast.data {
+        Data::Struct(strct) => derive_unaligned_struct(&ast, strct),
+        Data::Enum(enm) => derive_unaligned_enum(&ast, enm),
+        Data::Union(unn) => derive_unaligned_union(&ast, unn),
+    }
+    .into()
+}
+
+const STRUCT_UNION_ALLOWED_REPR_COMBINATIONS: &[&[StructRepr]] = &[
+    &[StructRepr::C],
+    &[StructRepr::Transparent],
+    &[StructRepr::Packed],
+    &[StructRepr::C, StructRepr::Packed],
+];
+
+// A struct is `FromZeroes` if:
+// - all fields are `FromZeroes`
+
+fn derive_from_zeroes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {
+    impl_block(ast, strct, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None)
+}
+
+// An enum is `FromZeroes` if:
+// - all of its variants are fieldless
+// - one of the variants has a discriminant of `0`
+
+fn derive_from_zeroes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream {
+    if !enm.is_c_like() {
+        return Error::new_spanned(ast, "only C-like enums can implement FromZeroes")
+            .to_compile_error();
+    }
+
+    let has_explicit_zero_discriminant =
+        enm.variants.iter().filter_map(|v| v.discriminant.as_ref()).any(|(_, e)| {
+            if let Expr::Lit(ExprLit { lit: Lit::Int(i), .. }) = e {
+                i.base10_parse::<usize>().ok() == Some(0)
+            } else {
+                false
+            }
+        });
+    // If the first variant of an enum does not specify its discriminant, it is set to zero:
+    // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
+    let has_implicit_zero_discriminant =
+        enm.variants.iter().next().map(|v| v.discriminant.is_none()) == Some(true);
+
+    if !has_explicit_zero_discriminant && !has_implicit_zero_discriminant {
+        return Error::new_spanned(
+            ast,
+            "FromZeroes only supported on enums with a variant that has a discriminant of `0`",
+        )
+        .to_compile_error();
+    }
+
+    impl_block(ast, enm, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None)
+}
+
+// Like structs, unions are `FromZeroes` if
+// - all fields are `FromZeroes`
+
+fn derive_from_zeroes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
+    impl_block(ast, unn, Trait::FromZeroes, RequireBoundedFields::Yes, false, None, None)
+}
+
+// A struct is `FromBytes` if:
+// - all fields are `FromBytes`
+
+fn derive_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {
+    impl_block(ast, strct, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None)
+}
+
+// An enum is `FromBytes` if:
+// - Every possible bit pattern must be valid, which means that every bit
+//   pattern must correspond to a different enum variant. Thus, for an enum
+//   whose layout takes up N bytes, there must be 2^N variants.
+// - Since we must know N, only representations which guarantee the layout's
+//   size are allowed. These are `repr(uN)` and `repr(iN)` (`repr(C)` implies an
+//   implementation-defined size). `usize` and `isize` technically guarantee the
+//   layout's size, but would require us to know how large those are on the
+//   target platform. This isn't terribly difficult - we could emit a const
+//   expression that could call `core::mem::size_of` in order to determine the
+//   size and check against the number of enum variants, but a) this would be
+//   platform-specific and, b) even on Rust's smallest bit width platform (32),
+//   this would require ~4 billion enum variants, which obviously isn't a thing.
+
+fn derive_from_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream {
+    if !enm.is_c_like() {
+        return Error::new_spanned(ast, "only C-like enums can implement FromBytes")
+            .to_compile_error();
+    }
+
+    let reprs = try_or_print!(ENUM_FROM_BYTES_CFG.validate_reprs(ast));
+
+    let variants_required = match reprs.as_slice() {
+        [EnumRepr::U8] | [EnumRepr::I8] => 1usize << 8,
+        [EnumRepr::U16] | [EnumRepr::I16] => 1usize << 16,
+        // `validate_reprs` has already validated that it's one of the preceding
+        // patterns.
+        _ => unreachable!(),
+    };
+    if enm.variants.len() != variants_required {
+        return Error::new_spanned(
+            ast,
+            format!(
+                "FromBytes only supported on {} enum with {} variants",
+                reprs[0], variants_required
+            ),
+        )
+        .to_compile_error();
+    }
+
+    impl_block(ast, enm, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None)
+}
+
+#[rustfmt::skip]
+const ENUM_FROM_BYTES_CFG: Config<EnumRepr> = {
+    use EnumRepr::*;
+    Config {
+        allowed_combinations_message: r#"FromBytes requires repr of "u8", "u16", "i8", or "i16""#,
+        derive_unaligned: false,
+        allowed_combinations: &[
+            &[U8],
+            &[U16],
+            &[I8],
+            &[I16],
+        ],
+        disallowed_but_legal_combinations: &[
+            &[C],
+            &[U32],
+            &[I32],
+            &[U64],
+            &[I64],
+            &[Usize],
+            &[Isize],
+        ],
+    }
+};
+
+// Like structs, unions are `FromBytes` if
+// - all fields are `FromBytes`
+
+fn derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
+    impl_block(ast, unn, Trait::FromBytes, RequireBoundedFields::Yes, false, None, None)
+}
+
+// A struct is `AsBytes` if:
+// - all fields are `AsBytes`
+// - `repr(C)` or `repr(transparent)` and
+//   - no padding (size of struct equals sum of size of field types)
+// - `repr(packed)`
+
+fn derive_as_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {
+    let reprs = try_or_print!(STRUCT_UNION_AS_BYTES_CFG.validate_reprs(ast));
+    let is_transparent = reprs.contains(&StructRepr::Transparent);
+    let is_packed = reprs.contains(&StructRepr::Packed);
+
+    // TODO(#10): Support type parameters for non-transparent, non-packed
+    // structs.
+    if !ast.generics.params.is_empty() && !is_transparent && !is_packed {
+        return Error::new(
+            Span::call_site(),
+            "unsupported on generic structs that are not repr(transparent) or repr(packed)",
+        )
+        .to_compile_error();
+    }
+
+    // We don't need a padding check if the struct is repr(transparent) or
+    // repr(packed).
+    // - repr(transparent): The layout and ABI of the whole struct is the same
+    //   as its only non-ZST field (meaning there's no padding outside of that
+    //   field) and we require that field to be `AsBytes` (meaning there's no
+    //   padding in that field).
+    // - repr(packed): Any inter-field padding bytes are removed, meaning that
+    //   any padding bytes would need to come from the fields, all of which
+    //   we require to be `AsBytes` (meaning they don't have any padding).
+    let padding_check = if is_transparent || is_packed { None } else { Some(PaddingCheck::Struct) };
+    impl_block(ast, strct, Trait::AsBytes, RequireBoundedFields::Yes, false, padding_check, None)
+}
+
+const STRUCT_UNION_AS_BYTES_CFG: Config<StructRepr> = Config {
+    // Since `disallowed_but_legal_combinations` is empty, this message will
+    // never actually be emitted.
+    allowed_combinations_message: r#"AsBytes requires either a) repr "C" or "transparent" with all fields implementing AsBytes or, b) repr "packed""#,
+    derive_unaligned: false,
+    allowed_combinations: STRUCT_UNION_ALLOWED_REPR_COMBINATIONS,
+    disallowed_but_legal_combinations: &[],
+};
+
+// An enum is `AsBytes` if it is C-like and has a defined repr.
+
+fn derive_as_bytes_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream {
+    if !enm.is_c_like() {
+        return Error::new_spanned(ast, "only C-like enums can implement AsBytes")
+            .to_compile_error();
+    }
+
+    // We don't care what the repr is; we only care that it is one of the
+    // allowed ones.
+    let _: Vec<repr::EnumRepr> = try_or_print!(ENUM_AS_BYTES_CFG.validate_reprs(ast));
+    impl_block(ast, enm, Trait::AsBytes, RequireBoundedFields::No, false, None, None)
+}
+
+#[rustfmt::skip]
+const ENUM_AS_BYTES_CFG: Config<EnumRepr> = {
+    use EnumRepr::*;
+    Config {
+        // Since `disallowed_but_legal_combinations` is empty, this message will
+        // never actually be emitted.
+        allowed_combinations_message: r#"AsBytes requires repr of "C", "u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", or "isize""#,
+        derive_unaligned: false,
+        allowed_combinations: &[
+            &[C],
+            &[U8],
+            &[U16],
+            &[I8],
+            &[I16],
+            &[U32],
+            &[I32],
+            &[U64],
+            &[I64],
+            &[Usize],
+            &[Isize],
+        ],
+        disallowed_but_legal_combinations: &[],
+    }
+};
+
+// A union is `AsBytes` if:
+// - all fields are `AsBytes`
+// - `repr(C)`, `repr(transparent)`, or `repr(packed)`
+// - no padding (size of union equals size of each field type)
+
+fn derive_as_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
+    // TODO(#10): Support type parameters.
+    if !ast.generics.params.is_empty() {
+        return Error::new(Span::call_site(), "unsupported on types with type parameters")
+            .to_compile_error();
+    }
+
+    try_or_print!(STRUCT_UNION_AS_BYTES_CFG.validate_reprs(ast));
+
+    impl_block(
+        ast,
+        unn,
+        Trait::AsBytes,
+        RequireBoundedFields::Yes,
+        false,
+        Some(PaddingCheck::Union),
+        None,
+    )
+}
+
+// A struct is `Unaligned` if:
+// - `repr(align)` is no more than 1 and either
+//   - `repr(C)` or `repr(transparent)` and
+//     - all fields `Unaligned`
+//   - `repr(packed)`
+
+fn derive_unaligned_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream {
+    let reprs = try_or_print!(STRUCT_UNION_UNALIGNED_CFG.validate_reprs(ast));
+    let require_trait_bounds_on_field_types = (!reprs.contains(&StructRepr::Packed)).into();
+
+    impl_block(ast, strct, Trait::Unaligned, require_trait_bounds_on_field_types, false, None, None)
+}
+
+const STRUCT_UNION_UNALIGNED_CFG: Config<StructRepr> = Config {
+    // Since `disallowed_but_legal_combinations` is empty, this message will
+    // never actually be emitted.
+    allowed_combinations_message: r#"Unaligned requires either a) repr "C" or "transparent" with all fields implementing Unaligned or, b) repr "packed""#,
+    derive_unaligned: true,
+    allowed_combinations: STRUCT_UNION_ALLOWED_REPR_COMBINATIONS,
+    disallowed_but_legal_combinations: &[],
+};
+
+// An enum is `Unaligned` if:
+// - No `repr(align(N > 1))`
+// - `repr(u8)` or `repr(i8)`
+
+fn derive_unaligned_enum(ast: &DeriveInput, enm: &DataEnum) -> proc_macro2::TokenStream {
+    if !enm.is_c_like() {
+        return Error::new_spanned(ast, "only C-like enums can implement Unaligned")
+            .to_compile_error();
+    }
+
+    // The only valid reprs are `u8` and `i8`, and optionally `align(1)`. We
+    // don't actually care what the reprs are so long as they satisfy that
+    // requirement.
+    let _: Vec<repr::EnumRepr> = try_or_print!(ENUM_UNALIGNED_CFG.validate_reprs(ast));
+
+    // C-like enums cannot currently have type parameters, so this value of true
+    // for `require_trait_bound_on_field_types` doesn't really do anything. But
+    // it's marginally more future-proof in case that restriction is lifted in
+    // the future.
+    impl_block(ast, enm, Trait::Unaligned, RequireBoundedFields::Yes, false, None, None)
+}
+
+#[rustfmt::skip]
+const ENUM_UNALIGNED_CFG: Config<EnumRepr> = {
+    use EnumRepr::*;
+    Config {
+        allowed_combinations_message:
+            r#"Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))"#,
+        derive_unaligned: true,
+        allowed_combinations: &[
+            &[U8],
+            &[I8],
+        ],
+        disallowed_but_legal_combinations: &[
+            &[C],
+            &[U16],
+            &[U32],
+            &[U64],
+            &[Usize],
+            &[I16],
+            &[I32],
+            &[I64],
+            &[Isize],
+        ],
+    }
+};
+
+// Like structs, a union is `Unaligned` if:
+// - `repr(align)` is no more than 1 and either
+//   - `repr(C)` or `repr(transparent)` and
+//     - all fields `Unaligned`
+//   - `repr(packed)`
+
+fn derive_unaligned_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::TokenStream {
+    let reprs = try_or_print!(STRUCT_UNION_UNALIGNED_CFG.validate_reprs(ast));
+    let require_trait_bound_on_field_types = (!reprs.contains(&StructRepr::Packed)).into();
+
+    impl_block(ast, unn, Trait::Unaligned, require_trait_bound_on_field_types, false, None, None)
+}
+
+// This enum describes what kind of padding check needs to be generated for the
+// associated impl.
+enum PaddingCheck {
+    // Check that the sum of the fields' sizes exactly equals the struct's size.
+    Struct,
+    // Check that the size of each field exactly equals the union's size.
+    Union,
+}
+
+impl PaddingCheck {
+    /// Returns the ident of the macro to call in order to validate that a type
+    /// passes the padding check encoded by `PaddingCheck`.
+    fn validator_macro_ident(&self) -> Ident {
+        let s = match self {
+            PaddingCheck::Struct => "struct_has_padding",
+            PaddingCheck::Union => "union_has_padding",
+        };
+
+        Ident::new(s, Span::call_site())
+    }
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum Trait {
+    KnownLayout,
+    FromZeroes,
+    FromBytes,
+    AsBytes,
+    Unaligned,
+}
+
+impl Trait {
+    fn ident(&self) -> Ident {
+        Ident::new(format!("{:?}", self).as_str(), Span::call_site())
+    }
+}
+
+#[derive(Debug, Eq, PartialEq)]
+enum RequireBoundedFields {
+    No,
+    Yes,
+    Trailing,
+}
+
+impl From<bool> for RequireBoundedFields {
+    fn from(do_require: bool) -> Self {
+        match do_require {
+            true => Self::Yes,
+            false => Self::No,
+        }
+    }
+}
+
+fn impl_block<D: DataExt>(
+    input: &DeriveInput,
+    data: &D,
+    trt: Trait,
+    require_trait_bound_on_field_types: RequireBoundedFields,
+    require_self_sized: bool,
+    padding_check: Option<PaddingCheck>,
+    extras: Option<proc_macro2::TokenStream>,
+) -> proc_macro2::TokenStream {
+    // In this documentation, we will refer to this hypothetical struct:
+    //
+    //   #[derive(FromBytes)]
+    //   struct Foo<T, I: Iterator>
+    //   where
+    //       T: Copy,
+    //       I: Clone,
+    //       I::Item: Clone,
+    //   {
+    //       a: u8,
+    //       b: T,
+    //       c: I::Item,
+    //   }
+    //
+    // We extract the field types, which in this case are `u8`, `T`, and
+    // `I::Item`. We re-use the existing parameters and where clauses. If
+    // `require_trait_bound == true` (as it is for `FromBytes), we add where
+    // bounds for each field's type:
+    //
+    //   impl<T, I: Iterator> FromBytes for Foo<T, I>
+    //   where
+    //       T: Copy,
+    //       I: Clone,
+    //       I::Item: Clone,
+    //       T: FromBytes,
+    //       I::Item: FromBytes,
+    //   {
+    //   }
+    //
+    // NOTE: It is standard practice to only emit bounds for the type parameters
+    // themselves, not for field types based on those parameters (e.g., `T` vs
+    // `T::Foo`). For a discussion of why this is standard practice, see
+    // https://github.com/rust-lang/rust/issues/26925.
+    //
+    // The reason we diverge from this standard is that doing it that way for us
+    // would be unsound. E.g., consider a type, `T` where `T: FromBytes` but
+    // `T::Foo: !FromBytes`. It would not be sound for us to accept a type with
+    // a `T::Foo` field as `FromBytes` simply because `T: FromBytes`.
+    //
+    // While there's no getting around this requirement for us, it does have the
+    // pretty serious downside that, when lifetimes are involved, the trait
+    // solver ties itself in knots:
+    //
+    //     #[derive(Unaligned)]
+    //     #[repr(C)]
+    //     struct Dup<'a, 'b> {
+    //         a: PhantomData<&'a u8>,
+    //         b: PhantomData<&'b u8>,
+    //     }
+    //
+    //     error[E0283]: type annotations required: cannot resolve `core::marker::PhantomData<&'a u8>: zerocopy::Unaligned`
+    //      --> src/main.rs:6:10
+    //       |
+    //     6 | #[derive(Unaligned)]
+    //       |          ^^^^^^^^^
+    //       |
+    //       = note: required by `zerocopy::Unaligned`
+
+    let type_ident = &input.ident;
+    let trait_ident = trt.ident();
+    let field_types = data.field_types();
+
+    let bound_tt = |ty| parse_quote!(#ty: ::zerocopy::#trait_ident);
+    let field_type_bounds: Vec<_> = match (require_trait_bound_on_field_types, &field_types[..]) {
+        (RequireBoundedFields::Yes, _) => field_types.iter().map(bound_tt).collect(),
+        (RequireBoundedFields::No, _) | (RequireBoundedFields::Trailing, []) => vec![],
+        (RequireBoundedFields::Trailing, [.., last]) => vec![bound_tt(last)],
+    };
+
+    // Don't bother emitting a padding check if there are no fields.
+    #[allow(
+        unstable_name_collisions, // See `BoolExt` below
+        clippy::incompatible_msrv, // https://github.com/rust-lang/rust-clippy/issues/12280
+    )]
+    let padding_check_bound = padding_check.and_then(|check| (!field_types.is_empty()).then_some(check)).map(|check| {
+        let fields = field_types.iter();
+        let validator_macro = check.validator_macro_ident();
+        parse_quote!(
+            ::zerocopy::macro_util::HasPadding<#type_ident, {::zerocopy::#validator_macro!(#type_ident, #(#fields),*)}>:
+                ::zerocopy::macro_util::ShouldBe<false>
+        )
+    });
+
+    let self_sized_bound = if require_self_sized { Some(parse_quote!(Self: Sized)) } else { None };
+
+    let bounds = input
+        .generics
+        .where_clause
+        .as_ref()
+        .map(|where_clause| where_clause.predicates.iter())
+        .into_iter()
+        .flatten()
+        .chain(field_type_bounds.iter())
+        .chain(padding_check_bound.iter())
+        .chain(self_sized_bound.iter());
+
+    // The parameters with trait bounds, but without type defaults.
+    let params = input.generics.params.clone().into_iter().map(|mut param| {
+        match &mut param {
+            GenericParam::Type(ty) => ty.default = None,
+            GenericParam::Const(cnst) => cnst.default = None,
+            GenericParam::Lifetime(_) => {}
+        }
+        quote!(#param)
+    });
+
+    // The identifiers of the parameters without trait bounds or type defaults.
+    let param_idents = input.generics.params.iter().map(|param| match param {
+        GenericParam::Type(ty) => {
+            let ident = &ty.ident;
+            quote!(#ident)
+        }
+        GenericParam::Lifetime(l) => {
+            let ident = &l.lifetime;
+            quote!(#ident)
+        }
+        GenericParam::Const(cnst) => {
+            let ident = &cnst.ident;
+            quote!({#ident})
+        }
+    });
+
+    quote! {
+        // TODO(#553): Add a test that generates a warning when
+        // `#[allow(deprecated)]` isn't present.
+        #[allow(deprecated)]
+        unsafe impl < #(#params),* > ::zerocopy::#trait_ident for #type_ident < #(#param_idents),* >
+        where
+            #(#bounds,)*
+        {
+            fn only_derive_is_allowed_to_implement_this_trait() {}
+
+            #extras
+        }
+    }
+}
+
+fn print_all_errors(errors: Vec<Error>) -> proc_macro2::TokenStream {
+    errors.iter().map(Error::to_compile_error).collect()
+}
+
+// A polyfill for `Option::then_some`, which was added after our MSRV.
+//
+// TODO(#67): Remove this once our MSRV is >= 1.62.
+#[allow(unused)]
+trait BoolExt {
+    fn then_some<T>(self, t: T) -> Option<T>;
+}
+
+#[allow(unused)]
+impl BoolExt for bool {
+    fn then_some<T>(self, t: T) -> Option<T> {
+        if self {
+            Some(t)
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_config_repr_orderings() {
+        // Validate that the repr lists in the various configs are in the
+        // canonical order. If they aren't, then our algorithm to look up in
+        // those lists won't work.
+
+        // TODO(https://github.com/rust-lang/rust/issues/53485): Remove once
+        // `Vec::is_sorted` is stabilized.
+        fn is_sorted_and_deduped<T: Clone + Ord>(ts: &[T]) -> bool {
+            let mut sorted = ts.to_vec();
+            sorted.sort();
+            sorted.dedup();
+            ts == sorted.as_slice()
+        }
+
+        fn elements_are_sorted_and_deduped<T: Clone + Ord>(lists: &[&[T]]) -> bool {
+            lists.iter().all(|list| is_sorted_and_deduped(list))
+        }
+
+        fn config_is_sorted<T: KindRepr + Clone>(config: &Config<T>) -> bool {
+            elements_are_sorted_and_deduped(config.allowed_combinations)
+                && elements_are_sorted_and_deduped(config.disallowed_but_legal_combinations)
+        }
+
+        assert!(config_is_sorted(&STRUCT_UNION_UNALIGNED_CFG));
+        assert!(config_is_sorted(&ENUM_FROM_BYTES_CFG));
+        assert!(config_is_sorted(&ENUM_UNALIGNED_CFG));
+    }
+
+    #[test]
+    fn test_config_repr_no_overlap() {
+        // Validate that no set of reprs appears in both the
+        // `allowed_combinations` and `disallowed_but_legal_combinations` lists.
+
+        fn overlap<T: Eq>(a: &[T], b: &[T]) -> bool {
+            a.iter().any(|elem| b.contains(elem))
+        }
+
+        fn config_overlaps<T: KindRepr + Eq>(config: &Config<T>) -> bool {
+            overlap(config.allowed_combinations, config.disallowed_but_legal_combinations)
+        }
+
+        assert!(!config_overlaps(&STRUCT_UNION_UNALIGNED_CFG));
+        assert!(!config_overlaps(&ENUM_FROM_BYTES_CFG));
+        assert!(!config_overlaps(&ENUM_UNALIGNED_CFG));
+    }
+}
diff --git a/extra_versions/crates/zerocopy-derive/src/repr.rs b/extra_versions/crates/zerocopy-derive/src/repr.rs
new file mode 100644
index 0000000..f4f2788
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/src/repr.rs
@@ -0,0 +1,311 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use core::fmt::{self, Display, Formatter};
+
+use {
+    proc_macro2::Span,
+    syn::punctuated::Punctuated,
+    syn::spanned::Spanned,
+    syn::token::Comma,
+    syn::{Attribute, DeriveInput, Error, LitInt, Meta},
+};
+
+pub struct Config<Repr: KindRepr> {
+    // A human-readable message describing what combinations of representations
+    // are allowed. This will be printed to the user if they use an invalid
+    // combination.
+    pub allowed_combinations_message: &'static str,
+    // Whether we're checking as part of `derive(Unaligned)`. If not, we can
+    // ignore `repr(align)`, which makes the code (and the list of valid repr
+    // combinations we have to enumerate) somewhat simpler. If we're checking
+    // for `Unaligned`, then in addition to checking against illegal
+    // combinations, we also check to see if there exists a `repr(align(N > 1))`
+    // attribute.
+    pub derive_unaligned: bool,
+    // Combinations which are valid for the trait.
+    pub allowed_combinations: &'static [&'static [Repr]],
+    // Combinations which are not valid for the trait, but are legal according
+    // to Rust. Any combination not in this or `allowed_combinations` is either
+    // illegal according to Rust or the behavior is unspecified. If the behavior
+    // is unspecified, it might become specified in the future, and that
+    // specification might not play nicely with our requirements. Thus, we
+    // reject combinations with unspecified behavior in addition to illegal
+    // combinations.
+    pub disallowed_but_legal_combinations: &'static [&'static [Repr]],
+}
+
+impl<R: KindRepr> Config<R> {
+    /// Validate that `input`'s representation attributes conform to the
+    /// requirements specified by this `Config`.
+    ///
+    /// `validate_reprs` extracts the `repr` attributes, validates that they
+    /// conform to the requirements of `self`, and returns them. Regardless of
+    /// whether `align` attributes are considered during validation, they are
+    /// stripped out of the returned value since no callers care about them.
+    pub fn validate_reprs(&self, input: &DeriveInput) -> Result<Vec<R>, Vec<Error>> {
+        let mut metas_reprs = reprs(&input.attrs)?;
+        metas_reprs.sort_by(|a: &(_, R), b| a.1.partial_cmp(&b.1).unwrap());
+
+        if self.derive_unaligned {
+            if let Some((meta, _)) =
+                metas_reprs.iter().find(|&repr: &&(_, R)| repr.1.is_align_gt_one())
+            {
+                return Err(vec![Error::new_spanned(
+                    meta,
+                    "cannot derive Unaligned with repr(align(N > 1))",
+                )]);
+            }
+        }
+
+        let mut metas = Vec::new();
+        let mut reprs = Vec::new();
+        metas_reprs.into_iter().filter(|(_, repr)| !repr.is_align()).for_each(|(meta, repr)| {
+            metas.push(meta);
+            reprs.push(repr)
+        });
+
+        if reprs.is_empty() {
+            // Use `Span::call_site` to report this error on the
+            // `#[derive(...)]` itself.
+            return Err(vec![Error::new(Span::call_site(), "must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout")]);
+        }
+
+        let initial_sp = metas[0].span();
+        let err_span = metas.iter().skip(1).try_fold(initial_sp, |sp, meta| sp.join(meta.span()));
+
+        if self.allowed_combinations.contains(&reprs.as_slice()) {
+            Ok(reprs)
+        } else if self.disallowed_but_legal_combinations.contains(&reprs.as_slice()) {
+            Err(vec![Error::new(
+                err_span.unwrap_or_else(|| input.span()),
+                self.allowed_combinations_message,
+            )])
+        } else {
+            Err(vec![Error::new(
+                err_span.unwrap_or_else(|| input.span()),
+                "conflicting representation hints",
+            )])
+        }
+    }
+}
+
+// The type of valid reprs for a particular kind (enum, struct, union).
+pub trait KindRepr: 'static + Sized + Ord {
+    fn is_align(&self) -> bool;
+    fn is_align_gt_one(&self) -> bool;
+    fn parse(meta: &Meta) -> syn::Result<Self>;
+}
+
+// Defines an enum for reprs which are valid for a given kind (structs, enums,
+// etc), and provide implementations of `KindRepr`, `Ord`, and `Display`, and
+// those traits' super-traits.
+macro_rules! define_kind_specific_repr {
+    ($type_name:expr, $repr_name:ident, [ $($repr_variant:ident),* ] , [ $($repr_variant_aligned:ident),* ]) => {
+        #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+        pub enum $repr_name {
+            $($repr_variant,)*
+            $($repr_variant_aligned(u64),)*
+        }
+
+        impl KindRepr for $repr_name {
+            fn is_align(&self) -> bool {
+                match self {
+                    $($repr_name::$repr_variant_aligned(_) => true,)*
+                    _ => false,
+                }
+            }
+
+            fn is_align_gt_one(&self) -> bool {
+                match self {
+                    // `packed(n)` only lowers alignment
+                    $repr_name::Align(n) => n > &1,
+                    _ => false,
+                }
+            }
+
+            fn parse(meta: &Meta) -> syn::Result<$repr_name> {
+                match Repr::from_meta(meta)? {
+                    $(Repr::$repr_variant => Ok($repr_name::$repr_variant),)*
+                    $(Repr::$repr_variant_aligned(u) => Ok($repr_name::$repr_variant_aligned(u)),)*
+                    _ => Err(Error::new_spanned(meta, concat!("unsupported representation for deriving FromBytes, AsBytes, or Unaligned on ", $type_name)))
+                }
+            }
+        }
+
+        // Define a stable ordering so we can canonicalize lists of reprs. The
+        // ordering itself doesn't matter so long as it's stable.
+        impl PartialOrd for $repr_name {
+            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+                Some(self.cmp(other))
+            }
+        }
+
+        impl Ord for $repr_name {
+            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+                format!("{:?}", self).cmp(&format!("{:?}", other))
+            }
+        }
+
+        impl core::fmt::Display for $repr_name {
+            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+                match self {
+                    $($repr_name::$repr_variant => Repr::$repr_variant,)*
+                    $($repr_name::$repr_variant_aligned(u) => Repr::$repr_variant_aligned(*u),)*
+                }.fmt(f)
+            }
+        }
+    }
+}
+
+define_kind_specific_repr!("a struct", StructRepr, [C, Transparent, Packed], [Align, PackedN]);
+define_kind_specific_repr!(
+    "an enum",
+    EnumRepr,
+    [C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize],
+    [Align]
+);
+
+// All representations known to Rust.
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub enum Repr {
+    U8,
+    U16,
+    U32,
+    U64,
+    Usize,
+    I8,
+    I16,
+    I32,
+    I64,
+    Isize,
+    C,
+    Transparent,
+    Packed,
+    PackedN(u64),
+    Align(u64),
+}
+
+impl Repr {
+    fn from_meta(meta: &Meta) -> Result<Repr, Error> {
+        let (path, list) = match meta {
+            Meta::Path(path) => (path, None),
+            Meta::List(list) => (&list.path, Some(list)),
+            _ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
+        };
+
+        let ident = path
+            .get_ident()
+            .ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;
+
+        Ok(match (ident.to_string().as_str(), list) {
+            ("u8", None) => Repr::U8,
+            ("u16", None) => Repr::U16,
+            ("u32", None) => Repr::U32,
+            ("u64", None) => Repr::U64,
+            ("usize", None) => Repr::Usize,
+            ("i8", None) => Repr::I8,
+            ("i16", None) => Repr::I16,
+            ("i32", None) => Repr::I32,
+            ("i64", None) => Repr::I64,
+            ("isize", None) => Repr::Isize,
+            ("C", None) => Repr::C,
+            ("transparent", None) => Repr::Transparent,
+            ("packed", None) => Repr::Packed,
+            ("packed", Some(list)) => {
+                Repr::PackedN(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
+            }
+            ("align", Some(list)) => {
+                Repr::Align(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
+            }
+            _ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
+        })
+    }
+}
+
+impl KindRepr for Repr {
+    fn is_align(&self) -> bool {
+        false
+    }
+
+    fn is_align_gt_one(&self) -> bool {
+        false
+    }
+
+    fn parse(meta: &Meta) -> syn::Result<Self> {
+        Self::from_meta(meta)
+    }
+}
+
+impl Display for Repr {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
+        if let Repr::Align(n) = self {
+            return write!(f, "repr(align({}))", n);
+        }
+        if let Repr::PackedN(n) = self {
+            return write!(f, "repr(packed({}))", n);
+        }
+        write!(
+            f,
+            "repr({})",
+            match self {
+                Repr::U8 => "u8",
+                Repr::U16 => "u16",
+                Repr::U32 => "u32",
+                Repr::U64 => "u64",
+                Repr::Usize => "usize",
+                Repr::I8 => "i8",
+                Repr::I16 => "i16",
+                Repr::I32 => "i32",
+                Repr::I64 => "i64",
+                Repr::Isize => "isize",
+                Repr::C => "C",
+                Repr::Transparent => "transparent",
+                Repr::Packed => "packed",
+                _ => unreachable!(),
+            }
+        )
+    }
+}
+
+pub(crate) fn reprs<R: KindRepr>(attrs: &[Attribute]) -> Result<Vec<(Meta, R)>, Vec<Error>> {
+    let mut reprs = Vec::new();
+    let mut errors = Vec::new();
+    for attr in attrs {
+        // Ignore documentation attributes.
+        if attr.path().is_ident("doc") {
+            continue;
+        }
+        if let Meta::List(ref meta_list) = attr.meta {
+            if meta_list.path.is_ident("repr") {
+                let parsed: Punctuated<Meta, Comma> =
+                    match meta_list.parse_args_with(Punctuated::parse_terminated) {
+                        Ok(parsed) => parsed,
+                        Err(_) => {
+                            errors.push(Error::new_spanned(
+                                &meta_list.tokens,
+                                "unrecognized representation hint",
+                            ));
+                            continue;
+                        }
+                    };
+                for meta in parsed {
+                    match R::parse(&meta) {
+                        Ok(repr) => reprs.push((meta, repr)),
+                        Err(err) => errors.push(err),
+                    }
+                }
+            }
+        }
+    }
+
+    if !errors.is_empty() {
+        return Err(errors);
+    }
+    Ok(reprs)
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/enum_as_bytes.rs b/extra_versions/crates/zerocopy-derive/tests/enum_as_bytes.rs
new file mode 100644
index 0000000..e305bc4
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/enum_as_bytes.rs
@@ -0,0 +1,101 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use {static_assertions::assert_impl_all, zerocopy::AsBytes};
+
+// An enum is `AsBytes` if if has a defined repr.
+
+#[derive(AsBytes)]
+#[repr(C)]
+enum C {
+    A,
+}
+
+assert_impl_all!(C: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(u8)]
+enum U8 {
+    A,
+}
+
+assert_impl_all!(U8: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(u16)]
+enum U16 {
+    A,
+}
+
+assert_impl_all!(U16: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(u32)]
+enum U32 {
+    A,
+}
+
+assert_impl_all!(U32: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(u64)]
+enum U64 {
+    A,
+}
+
+assert_impl_all!(U64: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(usize)]
+enum Usize {
+    A,
+}
+
+assert_impl_all!(Usize: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(i8)]
+enum I8 {
+    A,
+}
+
+assert_impl_all!(I8: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(i16)]
+enum I16 {
+    A,
+}
+
+assert_impl_all!(I16: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(i32)]
+enum I32 {
+    A,
+}
+
+assert_impl_all!(I32: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(i64)]
+enum I64 {
+    A,
+}
+
+assert_impl_all!(I64: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(isize)]
+enum Isize {
+    A,
+}
+
+assert_impl_all!(Isize: AsBytes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/enum_from_zeroes.rs b/extra_versions/crates/zerocopy-derive/tests/enum_from_zeroes.rs
new file mode 100644
index 0000000..c6bb675
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/enum_from_zeroes.rs
@@ -0,0 +1,35 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+mod util;
+
+use {static_assertions::assert_impl_all, zerocopy::FromZeroes};
+
+#[derive(FromZeroes)]
+enum Foo {
+    A,
+}
+
+assert_impl_all!(Foo: FromZeroes);
+
+#[derive(FromZeroes)]
+enum Bar {
+    A = 0,
+}
+
+assert_impl_all!(Bar: FromZeroes);
+
+#[derive(FromZeroes)]
+enum Baz {
+    A = 1,
+    B = 0,
+}
+
+assert_impl_all!(Baz: FromZeroes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/enum_known_layout.rs b/extra_versions/crates/zerocopy-derive/tests/enum_known_layout.rs
new file mode 100644
index 0000000..49a6765
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/enum_known_layout.rs
@@ -0,0 +1,46 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(warnings)]
+
+mod util;
+
+use {core::marker::PhantomData, static_assertions::assert_impl_all, zerocopy::KnownLayout};
+
+#[derive(KnownLayout)]
+enum Foo {
+    A,
+}
+
+assert_impl_all!(Foo: KnownLayout);
+
+#[derive(KnownLayout)]
+enum Bar {
+    A = 0,
+}
+
+assert_impl_all!(Bar: KnownLayout);
+
+#[derive(KnownLayout)]
+enum Baz {
+    A = 1,
+    B = 0,
+}
+
+assert_impl_all!(Baz: KnownLayout);
+
+// Deriving `KnownLayout` should work if the enum has bounded parameters.
+
+#[derive(KnownLayout)]
+#[repr(C)]
+enum WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout>
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + KnownLayout,
+{
+    Variant([T; N], PhantomData<&'a &'b ()>),
+}
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout);
diff --git a/extra_versions/crates/zerocopy-derive/tests/enum_unaligned.rs b/extra_versions/crates/zerocopy-derive/tests/enum_unaligned.rs
new file mode 100644
index 0000000..152ce27
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/enum_unaligned.rs
@@ -0,0 +1,47 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use {static_assertions::assert_impl_all, zerocopy::Unaligned};
+
+// An enum is `Unaligned` if:
+// - No `repr(align(N > 1))`
+// - `repr(u8)` or `repr(i8)`
+
+#[derive(Unaligned)]
+#[repr(u8)]
+enum Foo {
+    A,
+}
+
+assert_impl_all!(Foo: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(i8)]
+enum Bar {
+    A,
+}
+
+assert_impl_all!(Bar: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(u8, align(1))]
+enum Baz {
+    A,
+}
+
+assert_impl_all!(Baz: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(i8, align(1))]
+enum Blah {
+    B,
+}
+
+assert_impl_all!(Blah: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/hygiene.rs b/extra_versions/crates/zerocopy-derive/tests/hygiene.rs
new file mode 100644
index 0000000..b7b838d
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/hygiene.rs
@@ -0,0 +1,43 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// Make sure that macro hygiene will ensure that when we reference "zerocopy",
+// that will work properly even if they've renamed the crate and have not
+// imported its traits.
+
+#![allow(warnings)]
+
+extern crate zerocopy as _zerocopy;
+
+#[macro_use]
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use static_assertions::assert_impl_all;
+
+#[derive(
+    _zerocopy::KnownLayout, _zerocopy::FromZeroes, _zerocopy::FromBytes, _zerocopy::Unaligned,
+)]
+#[repr(C)]
+struct TypeParams<'a, T, I: Iterator> {
+    a: T,
+    c: I::Item,
+    d: u8,
+    e: PhantomData<&'a [u8]>,
+    f: PhantomData<&'static str>,
+    g: PhantomData<String>,
+}
+
+assert_impl_all!(
+    TypeParams<'static, (), IntoIter<()>>:
+        _zerocopy::KnownLayout,
+        _zerocopy::FromZeroes,
+        _zerocopy::FromBytes,
+        _zerocopy::Unaligned
+);
diff --git a/extra_versions/crates/zerocopy-derive/tests/paths_and_modules.rs b/extra_versions/crates/zerocopy-derive/tests/paths_and_modules.rs
new file mode 100644
index 0000000..a01983b
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/paths_and_modules.rs
@@ -0,0 +1,38 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
+
+// Ensure that types that are use'd and types that are referenced by path work.
+
+mod foo {
+    use zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned};
+
+    #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+    #[repr(C)]
+    pub struct Foo {
+        foo: u8,
+    }
+
+    #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+    #[repr(C)]
+    pub struct Bar {
+        bar: u8,
+    }
+}
+
+use foo::Foo;
+
+#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+#[repr(C)]
+struct Baz {
+    foo: Foo,
+    bar: foo::Bar,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/priv_in_pub.rs b/extra_versions/crates/zerocopy-derive/tests/priv_in_pub.rs
new file mode 100644
index 0000000..5f7d874
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/priv_in_pub.rs
@@ -0,0 +1,24 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use zerocopy::{AsBytes, FromBytes, FromZeroes, KnownLayout, Unaligned};
+
+// These derives do not result in E0446 as of Rust 1.59.0, because of
+// https://github.com/rust-lang/rust/pull/90586.
+//
+// This change eliminates one of the major downsides of emitting `where`
+// bounds for field types (i.e., the emission of E0446 for private field
+// types).
+
+#[derive(KnownLayout, AsBytes, FromZeroes, FromBytes, Unaligned)]
+#[repr(C)]
+pub struct Public(Private);
+
+#[derive(KnownLayout, AsBytes, FromZeroes, FromBytes, Unaligned)]
+#[repr(C)]
+struct Private(());
diff --git a/extra_versions/crates/zerocopy-derive/tests/struct_as_bytes.rs b/extra_versions/crates/zerocopy-derive/tests/struct_as_bytes.rs
new file mode 100644
index 0000000..3c71bf0
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/struct_as_bytes.rs
@@ -0,0 +1,161 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+mod util;
+
+use std::{marker::PhantomData, mem::ManuallyDrop, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::AsBytes};
+
+use self::util::AU16;
+
+// A struct is `AsBytes` if:
+// - all fields are `AsBytes`
+// - `repr(C)` or `repr(transparent)` and
+//   - no padding (size of struct equals sum of size of field types)
+// - `repr(packed)`
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct CZst;
+
+assert_impl_all!(CZst: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct C {
+    a: u8,
+    b: u8,
+    c: AU16,
+}
+
+assert_impl_all!(C: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(transparent)]
+struct Transparent {
+    a: u8,
+    b: CZst,
+}
+
+assert_impl_all!(Transparent: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(transparent)]
+struct TransparentGeneric<T: ?Sized> {
+    a: CZst,
+    b: T,
+}
+
+assert_impl_all!(TransparentGeneric<u64>: AsBytes);
+assert_impl_all!(TransparentGeneric<[u64]>: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+struct CZstPacked;
+
+assert_impl_all!(CZstPacked: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+struct CPacked {
+    a: u8,
+    // NOTE: The `u16` type is not guaranteed to have alignment 2, although it
+    // does on many platforms. However, to fix this would require a custom type
+    // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not
+    // allowed to transitively contain `#[repr(align(...))]` types. Thus, we
+    // have no choice but to use `u16` here. Luckily, these tests run in CI on
+    // platforms on which `u16` has alignment 2, so this isn't that big of a
+    // deal.
+    b: u16,
+}
+
+assert_impl_all!(CPacked: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed(2))]
+// The same caveats as for CPacked apply - we're assuming u64 is at least
+// 4-byte aligned by default. Without packed(2), this should fail, as there
+// would be padding between a/b assuming u64 is 4+ byte aligned.
+struct CPacked2 {
+    a: u16,
+    b: u64,
+}
+
+assert_impl_all!(CPacked2: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+struct CPackedGeneric<T, U: ?Sized> {
+    t: T,
+    // Unsized types stored in `repr(packed)` structs must not be dropped
+    // because dropping them in-place might be unsound depending on the
+    // alignment of the outer struct. Sized types can be dropped by first being
+    // moved to an aligned stack variable, but this isn't possible with unsized
+    // types.
+    u: ManuallyDrop<U>,
+}
+
+assert_impl_all!(CPackedGeneric<u8, AU16>: AsBytes);
+assert_impl_all!(CPackedGeneric<u8, [AU16]>: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(packed)]
+struct Packed {
+    a: u8,
+    // NOTE: The `u16` type is not guaranteed to have alignment 2, although it
+    // does on many platforms. However, to fix this would require a custom type
+    // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not
+    // allowed to transitively contain `#[repr(align(...))]` types. Thus, we
+    // have no choice but to use `u16` here. Luckily, these tests run in CI on
+    // platforms on which `u16` has alignment 2, so this isn't that big of a
+    // deal.
+    b: u16,
+}
+
+assert_impl_all!(Packed: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(packed)]
+struct PackedGeneric<T, U: ?Sized> {
+    t: T,
+    // Unsized types stored in `repr(packed)` structs must not be dropped
+    // because dropping them in-place might be unsound depending on the
+    // alignment of the outer struct. Sized types can be dropped by first being
+    // moved to an aligned stack variable, but this isn't possible with unsized
+    // types.
+    u: ManuallyDrop<U>,
+}
+
+assert_impl_all!(PackedGeneric<u8, AU16>: AsBytes);
+assert_impl_all!(PackedGeneric<u8, [AU16]>: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(transparent)]
+struct Unsized {
+    a: [u8],
+}
+
+assert_impl_all!(Unsized: AsBytes);
+
+// Deriving `AsBytes` should work if the struct has bounded parameters.
+
+#[derive(AsBytes)]
+#[repr(transparent)]
+struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + AsBytes>(
+    [T; N],
+    PhantomData<&'a &'b ()>,
+)
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + AsBytes;
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: AsBytes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/struct_from_bytes.rs b/extra_versions/crates/zerocopy-derive/tests/struct_from_bytes.rs
new file mode 100644
index 0000000..98f03d1
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/struct_from_bytes.rs
@@ -0,0 +1,79 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{FromBytes, FromZeroes},
+};
+
+use crate::util::AU16;
+
+// A struct is `FromBytes` if:
+// - all fields are `FromBytes`
+
+#[derive(FromZeroes, FromBytes)]
+struct Zst;
+
+assert_impl_all!(Zst: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+struct One {
+    a: u8,
+}
+
+assert_impl_all!(One: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+struct Two {
+    a: u8,
+    b: Zst,
+}
+
+assert_impl_all!(Two: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+struct Unsized {
+    a: [u8],
+}
+
+assert_impl_all!(Unsized: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+struct TypeParams<'a, T: ?Sized, I: Iterator> {
+    a: I::Item,
+    b: u8,
+    c: PhantomData<&'a [u8]>,
+    d: PhantomData<&'static str>,
+    e: PhantomData<String>,
+    f: T,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromBytes);
+assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: FromBytes);
+assert_impl_all!(TypeParams<'static, [AU16], IntoIter<()>>: FromBytes);
+
+// Deriving `FromBytes` should work if the struct has bounded parameters.
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(transparent)]
+struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromBytes>(
+    [T; N],
+    PhantomData<&'a &'b ()>,
+)
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + FromBytes;
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromBytes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/struct_from_zeroes.rs b/extra_versions/crates/zerocopy-derive/tests/struct_from_zeroes.rs
new file mode 100644
index 0000000..75d8245
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/struct_from_zeroes.rs
@@ -0,0 +1,77 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+#[macro_use]
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::FromZeroes};
+
+use crate::util::AU16;
+
+// A struct is `FromZeroes` if:
+// - all fields are `FromZeroes`
+
+#[derive(FromZeroes)]
+struct Zst;
+
+assert_impl_all!(Zst: FromZeroes);
+
+#[derive(FromZeroes)]
+struct One {
+    a: bool,
+}
+
+assert_impl_all!(One: FromZeroes);
+
+#[derive(FromZeroes)]
+struct Two {
+    a: bool,
+    b: Zst,
+}
+
+assert_impl_all!(Two: FromZeroes);
+
+#[derive(FromZeroes)]
+struct Unsized {
+    a: [u8],
+}
+
+assert_impl_all!(Unsized: FromZeroes);
+
+#[derive(FromZeroes)]
+struct TypeParams<'a, T: ?Sized, I: Iterator> {
+    a: I::Item,
+    b: u8,
+    c: PhantomData<&'a [u8]>,
+    d: PhantomData<&'static str>,
+    e: PhantomData<String>,
+    f: T,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromZeroes);
+assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: FromZeroes);
+assert_impl_all!(TypeParams<'static, [AU16], IntoIter<()>>: FromZeroes);
+
+// Deriving `FromZeroes` should work if the struct has bounded parameters.
+
+#[derive(FromZeroes)]
+#[repr(transparent)]
+struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromZeroes>(
+    [T; N],
+    PhantomData<&'a &'b ()>,
+)
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + FromZeroes;
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromZeroes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/struct_known_layout.rs b/extra_versions/crates/zerocopy-derive/tests/struct_known_layout.rs
new file mode 100644
index 0000000..68d1284
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/struct_known_layout.rs
@@ -0,0 +1,65 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(warnings)]
+
+#[macro_use]
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{DstLayout, KnownLayout},
+};
+
+use crate::util::AU16;
+
+#[derive(KnownLayout)]
+struct Zst;
+
+assert_impl_all!(Zst: KnownLayout);
+
+#[derive(KnownLayout)]
+struct One {
+    a: bool,
+}
+
+assert_impl_all!(One: KnownLayout);
+
+#[derive(KnownLayout)]
+struct Two {
+    a: bool,
+    b: Zst,
+}
+
+assert_impl_all!(Two: KnownLayout);
+
+#[derive(KnownLayout)]
+struct TypeParams<'a, T, I: Iterator> {
+    a: I::Item,
+    b: u8,
+    c: PhantomData<&'a [u8]>,
+    d: PhantomData<&'static str>,
+    e: PhantomData<String>,
+    f: T,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: KnownLayout);
+assert_impl_all!(TypeParams<'static, AU16, IntoIter<()>>: KnownLayout);
+
+// Deriving `KnownLayout` should work if the struct has bounded parameters.
+
+#[derive(KnownLayout)]
+#[repr(C)]
+struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout>(
+    [T; N],
+    PhantomData<&'a &'b ()>,
+)
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + KnownLayout;
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout);
diff --git a/extra_versions/crates/zerocopy-derive/tests/struct_unaligned.rs b/extra_versions/crates/zerocopy-derive/tests/struct_unaligned.rs
new file mode 100644
index 0000000..a7db432
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/struct_unaligned.rs
@@ -0,0 +1,100 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::Unaligned};
+
+use crate::util::AU16;
+
+// A struct is `Unaligned` if:
+// - `repr(align)` is no more than 1 and either
+//   - `repr(C)` or `repr(transparent)` and
+//     - all fields Unaligned
+//   - `repr(packed)`
+
+#[derive(Unaligned)]
+#[repr(C)]
+struct Foo {
+    a: u8,
+}
+
+assert_impl_all!(Foo: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct Bar {
+    a: u8,
+}
+
+assert_impl_all!(Bar: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(packed)]
+struct Baz {
+    // NOTE: The `u16` type is not guaranteed to have alignment 2, although it
+    // does on many platforms. However, to fix this would require a custom type
+    // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not
+    // allowed to transitively contain `#[repr(align(...))]` types. Thus, we
+    // have no choice but to use `u16` here. Luckily, these tests run in CI on
+    // platforms on which `u16` has alignment 2, so this isn't that big of a
+    // deal.
+    a: u16,
+}
+
+assert_impl_all!(Baz: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(C, align(1))]
+struct FooAlign {
+    a: u8,
+}
+
+assert_impl_all!(FooAlign: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct Unsized {
+    a: [u8],
+}
+
+assert_impl_all!(Unsized: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(C)]
+struct TypeParams<'a, T: ?Sized, I: Iterator> {
+    a: I::Item,
+    b: u8,
+    c: PhantomData<&'a [u8]>,
+    d: PhantomData<&'static str>,
+    e: PhantomData<String>,
+    f: T,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: Unaligned);
+assert_impl_all!(TypeParams<'static, u8, IntoIter<()>>: Unaligned);
+assert_impl_all!(TypeParams<'static, [u8], IntoIter<()>>: Unaligned);
+
+// Deriving `Unaligned` should work if the struct has bounded parameters.
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + Unaligned>(
+    [T; N],
+    PhantomData<&'a &'b ()>,
+)
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + Unaligned;
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/trybuild.rs b/extra_versions/crates/zerocopy-derive/tests/trybuild.rs
new file mode 100644
index 0000000..3ea1c3b
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/trybuild.rs
@@ -0,0 +1,19 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[test]
+#[cfg_attr(miri, ignore)]
+fn ui() {
+    let version = testutil::ToolchainVersion::extract_from_pwd().unwrap();
+    // See the doc comment on this method for an explanation of what this does
+    // and why we store source files in different directories.
+    let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning();
+
+    let t = trybuild::TestCases::new();
+    t.compile_fail(format!("tests/{source_files_dirname}/*.rs"));
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.rs
new file mode 100644
index 0000000..2084d92
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.rs
@@ -0,0 +1,40 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use core::marker::PhantomData;
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned},
+};
+
+use self::util::NotZerocopy;
+
+fn main() {}
+
+// Test generic transparent structs
+
+#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+#[repr(transparent)]
+struct TransparentStruct<T> {
+    inner: T,
+    _phantom: PhantomData<()>,
+}
+
+// It should be legal to derive these traits on a transparent struct, but it
+// must also ensure the traits are only implemented when the inner type
+// implements them.
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr
new file mode 100644
index 0000000..3b228b1
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr
@@ -0,0 +1,71 @@
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-msrv/derive_transparent.rs:37:1
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`
+   |
+note: required because of the requirements on the impl of `FromZeroes` for `TransparentStruct<NotZerocopy>`
+  --> tests/ui-msrv/derive_transparent.rs:27:19
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                   ^^^^^^^^^^
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-msrv/derive_transparent.rs:37:1
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all`
+   = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-msrv/derive_transparent.rs:38:1
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+note: required because of the requirements on the impl of `FromBytes` for `TransparentStruct<NotZerocopy>`
+  --> tests/ui-msrv/derive_transparent.rs:27:31
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                               ^^^^^^^^^
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-msrv/derive_transparent.rs:38:1
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all`
+   = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-msrv/derive_transparent.rs:39:1
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
+   |
+note: required because of the requirements on the impl of `AsBytes` for `TransparentStruct<NotZerocopy>`
+  --> tests/ui-msrv/derive_transparent.rs:27:10
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |          ^^^^^^^
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-msrv/derive_transparent.rs:39:1
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all`
+   = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied
+  --> tests/ui-msrv/derive_transparent.rs:40:1
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`
+   |
+note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct<NotZerocopy>`
+  --> tests/ui-msrv/derive_transparent.rs:27:42
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                                          ^^^^^^^^^
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-msrv/derive_transparent.rs:40:1
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::assert_impl_all`
+   = note: this error originates in the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.rs
new file mode 100644
index 0000000..31d5679
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.rs
@@ -0,0 +1,194 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+//
+// Generic errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr("foo")]
+enum Generic1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(foo)]
+enum Generic2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(transparent)]
+enum Generic3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u8, u16)]
+enum Generic4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+enum Generic5 {
+    A,
+}
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+enum FromZeroes1 {
+    A(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes2 {
+    A,
+    B(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes3 {
+    A = 1,
+    B,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(C)]
+enum FromBytes1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(usize)]
+enum FromBytes2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(isize)]
+enum FromBytes3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u32)]
+enum FromBytes4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i32)]
+enum FromBytes5 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u64)]
+enum FromBytes6 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i64)]
+enum FromBytes7 {
+    A,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+enum Unaligned1 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u16)]
+enum Unaligned2 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i16)]
+enum Unaligned3 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u32)]
+enum Unaligned4 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i32)]
+enum Unaligned5 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u64)]
+enum Unaligned6 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i64)]
+enum Unaligned7 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(usize)]
+enum Unaligned8 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(isize)]
+enum Unaligned9 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u8, align(2))]
+enum Unaligned10 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i8, align(2))]
+enum Unaligned11 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+enum Unaligned12 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+enum Unaligned13 {
+    A,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.stderr
new file mode 100644
index 0000000..39bde3f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum.stderr
@@ -0,0 +1,199 @@
+error: unrecognized representation hint
+  --> tests/ui-msrv/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error: unrecognized representation hint
+  --> tests/ui-msrv/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+
+error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum
+  --> tests/ui-msrv/enum.rs:31:8
+   |
+31 | #[repr(transparent)]
+   |        ^^^^^^^^^^^
+
+error: conflicting representation hints
+  --> tests/ui-msrv/enum.rs:37:1
+   |
+37 | #[repr(u8, u16)]
+   | ^
+
+error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout
+  --> tests/ui-msrv/enum.rs:42:22
+   |
+42 | #[derive(FromZeroes, FromBytes)]
+   |                      ^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-msrv/enum.rs:52:1
+   |
+52 | / enum FromZeroes1 {
+53 | |     A(u8),
+54 | | }
+   | |_^
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-msrv/enum.rs:57:1
+   |
+57 | / enum FromZeroes2 {
+58 | |     A,
+59 | |     B(u8),
+60 | | }
+   | |_^
+
+error: FromZeroes only supported on enums with a variant that has a discriminant of `0`
+  --> tests/ui-msrv/enum.rs:63:1
+   |
+63 | / enum FromZeroes3 {
+64 | |     A = 1,
+65 | |     B,
+66 | | }
+   | |_^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-msrv/enum.rs:73:8
+   |
+73 | #[repr(C)]
+   |        ^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-msrv/enum.rs:79:8
+   |
+79 | #[repr(usize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-msrv/enum.rs:85:8
+   |
+85 | #[repr(isize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-msrv/enum.rs:91:8
+   |
+91 | #[repr(u32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-msrv/enum.rs:97:8
+   |
+97 | #[repr(i32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-msrv/enum.rs:103:8
+    |
+103 | #[repr(u64)]
+    |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-msrv/enum.rs:109:8
+    |
+109 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:119:8
+    |
+119 | #[repr(C)]
+    |        ^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:125:8
+    |
+125 | #[repr(u16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:131:8
+    |
+131 | #[repr(i16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:137:8
+    |
+137 | #[repr(u32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:143:8
+    |
+143 | #[repr(i32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:149:8
+    |
+149 | #[repr(u64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:155:8
+    |
+155 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:161:8
+    |
+161 | #[repr(usize)]
+    |        ^^^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-msrv/enum.rs:167:8
+    |
+167 | #[repr(isize)]
+    |        ^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-msrv/enum.rs:173:12
+    |
+173 | #[repr(u8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-msrv/enum.rs:179:12
+    |
+179 | #[repr(i8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-msrv/enum.rs:185:18
+    |
+185 | #[repr(align(1), align(2))]
+    |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-msrv/enum.rs:191:8
+    |
+191 | #[repr(align(2), align(4))]
+    |        ^^^^^^^^
+
+error[E0565]: meta item in `repr` must be an identifier
+  --> tests/ui-msrv/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error[E0552]: unrecognized representation hint
+  --> tests/ui-msrv/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+
+error[E0566]: conflicting representation hints
+  --> tests/ui-msrv/enum.rs:37:8
+   |
+37 | #[repr(u8, u16)]
+   |        ^^  ^^^
+   |
+   = note: `#[deny(conflicting_repr_hints)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs
new file mode 100644
index 0000000..1b1bed3
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.rs
@@ -0,0 +1,272 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+#[derive(FromBytes)]
+#[repr(u8)]
+enum Foo {
+    Variant0,
+    Variant1,
+    Variant2,
+    Variant3,
+    Variant4,
+    Variant5,
+    Variant6,
+    Variant7,
+    Variant8,
+    Variant9,
+    Variant10,
+    Variant11,
+    Variant12,
+    Variant13,
+    Variant14,
+    Variant15,
+    Variant16,
+    Variant17,
+    Variant18,
+    Variant19,
+    Variant20,
+    Variant21,
+    Variant22,
+    Variant23,
+    Variant24,
+    Variant25,
+    Variant26,
+    Variant27,
+    Variant28,
+    Variant29,
+    Variant30,
+    Variant31,
+    Variant32,
+    Variant33,
+    Variant34,
+    Variant35,
+    Variant36,
+    Variant37,
+    Variant38,
+    Variant39,
+    Variant40,
+    Variant41,
+    Variant42,
+    Variant43,
+    Variant44,
+    Variant45,
+    Variant46,
+    Variant47,
+    Variant48,
+    Variant49,
+    Variant50,
+    Variant51,
+    Variant52,
+    Variant53,
+    Variant54,
+    Variant55,
+    Variant56,
+    Variant57,
+    Variant58,
+    Variant59,
+    Variant60,
+    Variant61,
+    Variant62,
+    Variant63,
+    Variant64,
+    Variant65,
+    Variant66,
+    Variant67,
+    Variant68,
+    Variant69,
+    Variant70,
+    Variant71,
+    Variant72,
+    Variant73,
+    Variant74,
+    Variant75,
+    Variant76,
+    Variant77,
+    Variant78,
+    Variant79,
+    Variant80,
+    Variant81,
+    Variant82,
+    Variant83,
+    Variant84,
+    Variant85,
+    Variant86,
+    Variant87,
+    Variant88,
+    Variant89,
+    Variant90,
+    Variant91,
+    Variant92,
+    Variant93,
+    Variant94,
+    Variant95,
+    Variant96,
+    Variant97,
+    Variant98,
+    Variant99,
+    Variant100,
+    Variant101,
+    Variant102,
+    Variant103,
+    Variant104,
+    Variant105,
+    Variant106,
+    Variant107,
+    Variant108,
+    Variant109,
+    Variant110,
+    Variant111,
+    Variant112,
+    Variant113,
+    Variant114,
+    Variant115,
+    Variant116,
+    Variant117,
+    Variant118,
+    Variant119,
+    Variant120,
+    Variant121,
+    Variant122,
+    Variant123,
+    Variant124,
+    Variant125,
+    Variant126,
+    Variant127,
+    Variant128,
+    Variant129,
+    Variant130,
+    Variant131,
+    Variant132,
+    Variant133,
+    Variant134,
+    Variant135,
+    Variant136,
+    Variant137,
+    Variant138,
+    Variant139,
+    Variant140,
+    Variant141,
+    Variant142,
+    Variant143,
+    Variant144,
+    Variant145,
+    Variant146,
+    Variant147,
+    Variant148,
+    Variant149,
+    Variant150,
+    Variant151,
+    Variant152,
+    Variant153,
+    Variant154,
+    Variant155,
+    Variant156,
+    Variant157,
+    Variant158,
+    Variant159,
+    Variant160,
+    Variant161,
+    Variant162,
+    Variant163,
+    Variant164,
+    Variant165,
+    Variant166,
+    Variant167,
+    Variant168,
+    Variant169,
+    Variant170,
+    Variant171,
+    Variant172,
+    Variant173,
+    Variant174,
+    Variant175,
+    Variant176,
+    Variant177,
+    Variant178,
+    Variant179,
+    Variant180,
+    Variant181,
+    Variant182,
+    Variant183,
+    Variant184,
+    Variant185,
+    Variant186,
+    Variant187,
+    Variant188,
+    Variant189,
+    Variant190,
+    Variant191,
+    Variant192,
+    Variant193,
+    Variant194,
+    Variant195,
+    Variant196,
+    Variant197,
+    Variant198,
+    Variant199,
+    Variant200,
+    Variant201,
+    Variant202,
+    Variant203,
+    Variant204,
+    Variant205,
+    Variant206,
+    Variant207,
+    Variant208,
+    Variant209,
+    Variant210,
+    Variant211,
+    Variant212,
+    Variant213,
+    Variant214,
+    Variant215,
+    Variant216,
+    Variant217,
+    Variant218,
+    Variant219,
+    Variant220,
+    Variant221,
+    Variant222,
+    Variant223,
+    Variant224,
+    Variant225,
+    Variant226,
+    Variant227,
+    Variant228,
+    Variant229,
+    Variant230,
+    Variant231,
+    Variant232,
+    Variant233,
+    Variant234,
+    Variant235,
+    Variant236,
+    Variant237,
+    Variant238,
+    Variant239,
+    Variant240,
+    Variant241,
+    Variant242,
+    Variant243,
+    Variant244,
+    Variant245,
+    Variant246,
+    Variant247,
+    Variant248,
+    Variant249,
+    Variant250,
+    Variant251,
+    Variant252,
+    Variant253,
+    Variant254,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr
new file mode 100644
index 0000000..ff828dc
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/enum_from_bytes_u8_too_few.stderr
@@ -0,0 +1,11 @@
+error: FromBytes only supported on repr(u8) enum with 256 variants
+   --> tests/ui-msrv/enum_from_bytes_u8_too_few.rs:15:1
+    |
+15  | / #[repr(u8)]
+16  | | enum Foo {
+17  | |     Variant0,
+18  | |     Variant1,
+...   |
+271 | |     Variant254,
+272 | | }
+    | |_^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs
new file mode 100644
index 0000000..cd65a6e
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::{NotZerocopy, AU16};
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+struct FromZeroes1 {
+    value: NotZerocopy,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromBytes)]
+struct FromBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned1 {
+    aligned: AU16,
+}
+
+// This specifically tests a bug we had in an old version of the code in which
+// the trait bound would only be enforced for the first field's type.
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned2 {
+    unaligned: u8,
+    aligned: AU16,
+}
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct Unaligned3 {
+    aligned: AU16,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr
new file mode 100644
index 0000000..39dbcd1
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr
@@ -0,0 +1,74 @@
+warning: unused import: `zerocopy::KnownLayout`
+  --> tests/ui-msrv/late_compile_pass.rs:16:5
+   |
+16 | use zerocopy::KnownLayout;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:28:10
+   |
+28 | #[derive(FromZeroes)]
+   |          ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1`
+   |
+note: required by a bound in `FromBytes`
+  --> $WORKSPACE/src/lib.rs
+   |
+   | pub unsafe trait FromBytes: FromZeroes {
+   |                             ^^^^^^^^^^ required by this bound in `FromBytes`
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:46:10
+   |
+46 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:56:10
+   |
+56 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:64:10
+   |
+64 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-msrv/late_compile_pass.rs:71:10
+   |
+71 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs
new file mode 100644
index 0000000..e0c4bc5
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs
@@ -0,0 +1,61 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// KnownLayout errors
+//
+
+fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              N |        N |      KL04 |
+#[derive(KnownLayout)]
+struct KL04<T: ?Sized>(u8, T);
+
+fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              Y |        N |      KL06 |
+#[derive(KnownLayout)]
+struct KL06<T: ?Sized + KnownLayout>(u8, T);
+
+fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        N |      KL12 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL12<T: ?Sized>(u8, T);
+
+fn test_kl12<T: ?Sized>(kl: &KL12<T>) {
+    assert_kl(kl)
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        Y |      KL13 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL13<T>(u8, T);
+
+fn test_kl13<T>(t: T) -> impl KnownLayout {
+    KL13(0u8, t)
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr
new file mode 100644
index 0000000..5aa2cde
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr
@@ -0,0 +1,104 @@
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-msrv/mid_compile_pass.rs:59:26
+   |
+59 | fn test_kl13<T>(t: T) -> impl KnownLayout {
+   |                          ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`
+   |
+note: required because of the requirements on the impl of `KnownLayout` for `KL13<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:55:10
+   |
+55 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+59 | fn test_kl13<T: zerocopy::KnownLayout>(t: T) -> impl KnownLayout {
+   |               +++++++++++++++++++++++
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-msrv/mid_compile_pass.rs:31:15
+   |
+30 | fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+   |              - this type parameter needs to be `std::marker::Sized`
+31 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL04<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:28:8
+   |
+28 | struct KL04<T: ?Sized>(u8, T);
+   |        ^^^^
+note: required because of the requirements on the impl of `KnownLayout` for `KL04<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:27:10
+   |
+27 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^
+note: required by a bound in `assert_kl`
+  --> tests/ui-msrv/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+30 - fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+30 + fn test_kl04<T>(kl: &KL04<T>) {
+   |
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-msrv/mid_compile_pass.rs:40:15
+   |
+39 | fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+   |              - this type parameter needs to be `std::marker::Sized`
+40 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL06<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:37:8
+   |
+37 | struct KL06<T: ?Sized + KnownLayout>(u8, T);
+   |        ^^^^
+note: required because of the requirements on the impl of `KnownLayout` for `KL06<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^
+note: required by a bound in `assert_kl`
+  --> tests/ui-msrv/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+39 - fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+39 + fn test_kl06<T: KnownLayout>(kl: &KL06<T>) {
+   |
+
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-msrv/mid_compile_pass.rs:50:15
+   |
+50 |     assert_kl(kl)
+   |     --------- ^^ the trait `KnownLayout` is not implemented for `T`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because of the requirements on the impl of `KnownLayout` for `KL12<T>`
+  --> tests/ui-msrv/mid_compile_pass.rs:45:10
+   |
+45 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^
+note: required by a bound in `assert_kl`
+  --> tests/ui-msrv/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting this bound
+   |
+49 | fn test_kl12<T: ?Sized + zerocopy::KnownLayout>(kl: &KL12<T>) {
+   |                        +++++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.rs
new file mode 100644
index 0000000..c76dc7f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.rs
@@ -0,0 +1,99 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use zerocopy::KnownLayout;
+
+use self::util::AU16;
+
+fn main() {}
+
+//
+// KnownLayout errors
+//
+
+struct NotKnownLayout;
+
+struct NotKnownLayoutDst([u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              N |        N |      KL00 |
+#[derive(KnownLayout)]
+struct KL00(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              Y |        N |      KL02 |
+#[derive(KnownLayout)]
+struct KL02(u8, [u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        N |      KL08 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL08(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        Y |      KL09 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL09(NotKnownLayout, NotKnownLayout);
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1<T>(T);
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes2 {
+    foo: u8,
+    bar: AU16,
+}
+
+#[derive(AsBytes)]
+#[repr(C, packed(2))]
+struct AsBytes3 {
+    foo: u8,
+    // We'd prefer to use AU64 here, but you can't use aligned types in
+    // packed structs.
+    bar: u64,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+struct Unaligned1;
+
+#[derive(Unaligned)]
+#[repr(transparent, align(2))]
+struct Unaligned2 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+struct Unaligned3;
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4;
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5;
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.stderr
new file mode 100644
index 0000000..f4a435d
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/struct.stderr
@@ -0,0 +1,113 @@
+error: unsupported on generic structs that are not repr(transparent) or repr(packed)
+  --> tests/ui-msrv/struct.rs:55:10
+   |
+55 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/struct.rs:80:11
+   |
+80 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/struct.rs:84:21
+   |
+84 | #[repr(transparent, align(2))]
+   |                     ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/struct.rs:90:16
+   |
+90 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/struct.rs:94:18
+   |
+94 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/struct.rs:98:8
+   |
+98 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0692]: transparent struct cannot have other repr hints
+  --> tests/ui-msrv/struct.rs:84:8
+   |
+84 | #[repr(transparent, align(2))]
+   |        ^^^^^^^^^^^  ^^^^^^^^
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/struct.rs:31:10
+   |
+31 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `KL00`
+  --> tests/ui-msrv/struct.rs:32:8
+   |
+32 | struct KL00(u8, NotKnownLayoutDst);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/struct.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `KL02`
+  --> tests/ui-msrv/struct.rs:37:8
+   |
+37 | struct KL02(u8, [u8]);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied
+  --> tests/ui-msrv/struct.rs:41:10
+   |
+41 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied
+  --> tests/ui-msrv/struct.rs:47:10
+   |
+47 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout`
+   |
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-msrv/struct.rs:59:10
+   |
+59 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the following implementations were found:
+             <HasPadding<T, VALUE> as ShouldBe<VALUE>>
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-msrv/struct.rs:66:10
+   |
+66 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
+   |
+   = help: the following implementations were found:
+             <HasPadding<T, VALUE> as ShouldBe<VALUE>>
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.rs b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.rs
new file mode 100644
index 0000000..8938e78
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.rs
@@ -0,0 +1,73 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::AU16;
+use std::mem::ManuallyDrop;
+
+fn main() {}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes1<T> {
+    foo: ManuallyDrop<T>,
+}
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes2 {
+    foo: u8,
+    bar: [u8; 2],
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+union Unaligned1 {
+    foo: i16,
+    bar: AU16,
+}
+
+// Transparent unions are unstable; see issue #60405
+// <https://github.com/rust-lang/rust/issues/60405> for more information.
+
+// #[derive(Unaligned)]
+// #[repr(transparent, align(2))]
+// union Unaligned2 {
+//     foo: u8,
+// }
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+union Unaligned3 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5 {
+    foo: u8,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.stderr
new file mode 100644
index 0000000..3e13059
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-msrv/union.stderr
@@ -0,0 +1,42 @@
+error: unsupported on types with type parameters
+  --> tests/ui-msrv/union.rs:24:10
+   |
+24 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/union.rs:42:11
+   |
+42 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/union.rs:58:16
+   |
+58 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/union.rs:64:18
+   |
+64 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-msrv/union.rs:70:8
+   |
+70 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-msrv/union.rs:30:10
+   |
+30 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the following implementations were found:
+             <HasPadding<T, VALUE> as ShouldBe<VALUE>>
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.rs
new file mode 100644
index 0000000..2084d92
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.rs
@@ -0,0 +1,40 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use core::marker::PhantomData;
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned},
+};
+
+use self::util::NotZerocopy;
+
+fn main() {}
+
+// Test generic transparent structs
+
+#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+#[repr(transparent)]
+struct TransparentStruct<T> {
+    inner: T,
+    _phantom: PhantomData<()>,
+}
+
+// It should be legal to derive these traits on a transparent struct, but it
+// must also ensure the traits are only implemented when the inner type
+// implements them.
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr
new file mode 100644
index 0000000..86533b2
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr
@@ -0,0 +1,111 @@
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-nightly/derive_transparent.rs:37:18
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: FromZeroes`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `FromZeroes`
+  --> tests/ui-nightly/derive_transparent.rs:27:19
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                   ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-nightly/derive_transparent.rs:37:1
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-nightly/derive_transparent.rs:38:18
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: FromBytes`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `FromBytes`
+  --> tests/ui-nightly/derive_transparent.rs:27:31
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                               ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-nightly/derive_transparent.rs:38:1
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-nightly/derive_transparent.rs:39:18
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: AsBytes`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `AsBytes`
+  --> tests/ui-nightly/derive_transparent.rs:27:10
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |          ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-nightly/derive_transparent.rs:39:1
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied
+  --> tests/ui-nightly/derive_transparent.rs:40:18
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: Unaligned`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `Unaligned`
+  --> tests/ui-nightly/derive_transparent.rs:27:42
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                                          ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-nightly/derive_transparent.rs:40:1
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.rs
new file mode 100644
index 0000000..31d5679
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.rs
@@ -0,0 +1,194 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+//
+// Generic errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr("foo")]
+enum Generic1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(foo)]
+enum Generic2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(transparent)]
+enum Generic3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u8, u16)]
+enum Generic4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+enum Generic5 {
+    A,
+}
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+enum FromZeroes1 {
+    A(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes2 {
+    A,
+    B(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes3 {
+    A = 1,
+    B,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(C)]
+enum FromBytes1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(usize)]
+enum FromBytes2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(isize)]
+enum FromBytes3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u32)]
+enum FromBytes4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i32)]
+enum FromBytes5 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u64)]
+enum FromBytes6 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i64)]
+enum FromBytes7 {
+    A,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+enum Unaligned1 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u16)]
+enum Unaligned2 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i16)]
+enum Unaligned3 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u32)]
+enum Unaligned4 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i32)]
+enum Unaligned5 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u64)]
+enum Unaligned6 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i64)]
+enum Unaligned7 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(usize)]
+enum Unaligned8 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(isize)]
+enum Unaligned9 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u8, align(2))]
+enum Unaligned10 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i8, align(2))]
+enum Unaligned11 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+enum Unaligned12 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+enum Unaligned13 {
+    A,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.stderr
new file mode 100644
index 0000000..a4d5edf
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum.stderr
@@ -0,0 +1,201 @@
+error: unrecognized representation hint
+  --> tests/ui-nightly/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error: unrecognized representation hint
+  --> tests/ui-nightly/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+
+error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum
+  --> tests/ui-nightly/enum.rs:31:8
+   |
+31 | #[repr(transparent)]
+   |        ^^^^^^^^^^^
+
+error: conflicting representation hints
+  --> tests/ui-nightly/enum.rs:37:8
+   |
+37 | #[repr(u8, u16)]
+   |        ^^^^^^^
+
+error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout
+  --> tests/ui-nightly/enum.rs:42:22
+   |
+42 | #[derive(FromZeroes, FromBytes)]
+   |                      ^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-nightly/enum.rs:52:1
+   |
+52 | / enum FromZeroes1 {
+53 | |     A(u8),
+54 | | }
+   | |_^
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-nightly/enum.rs:57:1
+   |
+57 | / enum FromZeroes2 {
+58 | |     A,
+59 | |     B(u8),
+60 | | }
+   | |_^
+
+error: FromZeroes only supported on enums with a variant that has a discriminant of `0`
+  --> tests/ui-nightly/enum.rs:63:1
+   |
+63 | / enum FromZeroes3 {
+64 | |     A = 1,
+65 | |     B,
+66 | | }
+   | |_^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-nightly/enum.rs:73:8
+   |
+73 | #[repr(C)]
+   |        ^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-nightly/enum.rs:79:8
+   |
+79 | #[repr(usize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-nightly/enum.rs:85:8
+   |
+85 | #[repr(isize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-nightly/enum.rs:91:8
+   |
+91 | #[repr(u32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-nightly/enum.rs:97:8
+   |
+97 | #[repr(i32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-nightly/enum.rs:103:8
+    |
+103 | #[repr(u64)]
+    |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-nightly/enum.rs:109:8
+    |
+109 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:119:8
+    |
+119 | #[repr(C)]
+    |        ^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:125:8
+    |
+125 | #[repr(u16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:131:8
+    |
+131 | #[repr(i16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:137:8
+    |
+137 | #[repr(u32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:143:8
+    |
+143 | #[repr(i32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:149:8
+    |
+149 | #[repr(u64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:155:8
+    |
+155 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:161:8
+    |
+161 | #[repr(usize)]
+    |        ^^^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-nightly/enum.rs:167:8
+    |
+167 | #[repr(isize)]
+    |        ^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-nightly/enum.rs:173:12
+    |
+173 | #[repr(u8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-nightly/enum.rs:179:12
+    |
+179 | #[repr(i8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-nightly/enum.rs:185:18
+    |
+185 | #[repr(align(1), align(2))]
+    |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-nightly/enum.rs:191:8
+    |
+191 | #[repr(align(2), align(4))]
+    |        ^^^^^^^^
+
+error[E0565]: meta item in `repr` must be an identifier
+  --> tests/ui-nightly/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error[E0552]: unrecognized representation hint
+  --> tests/ui-nightly/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+   |
+   = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0566]: conflicting representation hints
+  --> tests/ui-nightly/enum.rs:37:8
+   |
+37 | #[repr(u8, u16)]
+   |        ^^  ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
+   = note: `#[deny(conflicting_repr_hints)]` on by default
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs
new file mode 100644
index 0000000..1b1bed3
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.rs
@@ -0,0 +1,272 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+#[derive(FromBytes)]
+#[repr(u8)]
+enum Foo {
+    Variant0,
+    Variant1,
+    Variant2,
+    Variant3,
+    Variant4,
+    Variant5,
+    Variant6,
+    Variant7,
+    Variant8,
+    Variant9,
+    Variant10,
+    Variant11,
+    Variant12,
+    Variant13,
+    Variant14,
+    Variant15,
+    Variant16,
+    Variant17,
+    Variant18,
+    Variant19,
+    Variant20,
+    Variant21,
+    Variant22,
+    Variant23,
+    Variant24,
+    Variant25,
+    Variant26,
+    Variant27,
+    Variant28,
+    Variant29,
+    Variant30,
+    Variant31,
+    Variant32,
+    Variant33,
+    Variant34,
+    Variant35,
+    Variant36,
+    Variant37,
+    Variant38,
+    Variant39,
+    Variant40,
+    Variant41,
+    Variant42,
+    Variant43,
+    Variant44,
+    Variant45,
+    Variant46,
+    Variant47,
+    Variant48,
+    Variant49,
+    Variant50,
+    Variant51,
+    Variant52,
+    Variant53,
+    Variant54,
+    Variant55,
+    Variant56,
+    Variant57,
+    Variant58,
+    Variant59,
+    Variant60,
+    Variant61,
+    Variant62,
+    Variant63,
+    Variant64,
+    Variant65,
+    Variant66,
+    Variant67,
+    Variant68,
+    Variant69,
+    Variant70,
+    Variant71,
+    Variant72,
+    Variant73,
+    Variant74,
+    Variant75,
+    Variant76,
+    Variant77,
+    Variant78,
+    Variant79,
+    Variant80,
+    Variant81,
+    Variant82,
+    Variant83,
+    Variant84,
+    Variant85,
+    Variant86,
+    Variant87,
+    Variant88,
+    Variant89,
+    Variant90,
+    Variant91,
+    Variant92,
+    Variant93,
+    Variant94,
+    Variant95,
+    Variant96,
+    Variant97,
+    Variant98,
+    Variant99,
+    Variant100,
+    Variant101,
+    Variant102,
+    Variant103,
+    Variant104,
+    Variant105,
+    Variant106,
+    Variant107,
+    Variant108,
+    Variant109,
+    Variant110,
+    Variant111,
+    Variant112,
+    Variant113,
+    Variant114,
+    Variant115,
+    Variant116,
+    Variant117,
+    Variant118,
+    Variant119,
+    Variant120,
+    Variant121,
+    Variant122,
+    Variant123,
+    Variant124,
+    Variant125,
+    Variant126,
+    Variant127,
+    Variant128,
+    Variant129,
+    Variant130,
+    Variant131,
+    Variant132,
+    Variant133,
+    Variant134,
+    Variant135,
+    Variant136,
+    Variant137,
+    Variant138,
+    Variant139,
+    Variant140,
+    Variant141,
+    Variant142,
+    Variant143,
+    Variant144,
+    Variant145,
+    Variant146,
+    Variant147,
+    Variant148,
+    Variant149,
+    Variant150,
+    Variant151,
+    Variant152,
+    Variant153,
+    Variant154,
+    Variant155,
+    Variant156,
+    Variant157,
+    Variant158,
+    Variant159,
+    Variant160,
+    Variant161,
+    Variant162,
+    Variant163,
+    Variant164,
+    Variant165,
+    Variant166,
+    Variant167,
+    Variant168,
+    Variant169,
+    Variant170,
+    Variant171,
+    Variant172,
+    Variant173,
+    Variant174,
+    Variant175,
+    Variant176,
+    Variant177,
+    Variant178,
+    Variant179,
+    Variant180,
+    Variant181,
+    Variant182,
+    Variant183,
+    Variant184,
+    Variant185,
+    Variant186,
+    Variant187,
+    Variant188,
+    Variant189,
+    Variant190,
+    Variant191,
+    Variant192,
+    Variant193,
+    Variant194,
+    Variant195,
+    Variant196,
+    Variant197,
+    Variant198,
+    Variant199,
+    Variant200,
+    Variant201,
+    Variant202,
+    Variant203,
+    Variant204,
+    Variant205,
+    Variant206,
+    Variant207,
+    Variant208,
+    Variant209,
+    Variant210,
+    Variant211,
+    Variant212,
+    Variant213,
+    Variant214,
+    Variant215,
+    Variant216,
+    Variant217,
+    Variant218,
+    Variant219,
+    Variant220,
+    Variant221,
+    Variant222,
+    Variant223,
+    Variant224,
+    Variant225,
+    Variant226,
+    Variant227,
+    Variant228,
+    Variant229,
+    Variant230,
+    Variant231,
+    Variant232,
+    Variant233,
+    Variant234,
+    Variant235,
+    Variant236,
+    Variant237,
+    Variant238,
+    Variant239,
+    Variant240,
+    Variant241,
+    Variant242,
+    Variant243,
+    Variant244,
+    Variant245,
+    Variant246,
+    Variant247,
+    Variant248,
+    Variant249,
+    Variant250,
+    Variant251,
+    Variant252,
+    Variant253,
+    Variant254,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr
new file mode 100644
index 0000000..50cf0e7
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/enum_from_bytes_u8_too_few.stderr
@@ -0,0 +1,11 @@
+error: FromBytes only supported on repr(u8) enum with 256 variants
+   --> tests/ui-nightly/enum_from_bytes_u8_too_few.rs:15:1
+    |
+15  | / #[repr(u8)]
+16  | | enum Foo {
+17  | |     Variant0,
+18  | |     Variant1,
+...   |
+271 | |     Variant254,
+272 | | }
+    | |_^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs
new file mode 100644
index 0000000..cd65a6e
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::{NotZerocopy, AU16};
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+struct FromZeroes1 {
+    value: NotZerocopy,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromBytes)]
+struct FromBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned1 {
+    aligned: AU16,
+}
+
+// This specifically tests a bug we had in an old version of the code in which
+// the trait bound would only be enforced for the first field's type.
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned2 {
+    unaligned: u8,
+    aligned: AU16,
+}
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct Unaligned3 {
+    aligned: AU16,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr
new file mode 100644
index 0000000..8d4e338
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr
@@ -0,0 +1,168 @@
+warning: unused import: `zerocopy::KnownLayout`
+  --> tests/ui-nightly/late_compile_pass.rs:16:5
+   |
+16 | use zerocopy::KnownLayout;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:28:10
+   |
+28 | #[derive(FromZeroes)]
+   |          ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             FromZeroes1
+             I128<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             FromBytes1
+             I128<O>
+             I16<O>
+             I32<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             FromZeroes1
+             I128<O>
+           and $N others
+note: required by a bound in `FromBytes`
+  --> $WORKSPACE/src/lib.rs
+   |
+   | pub unsafe trait FromBytes: FromZeroes {
+   |                             ^^^^^^^^^^ required by this bound in `FromBytes`
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:46:10
+   |
+46 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             AsBytes1
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:56:10
+   |
+56 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:64:10
+   |
+64 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-nightly/late_compile_pass.rs:71:10
+   |
+71 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs
new file mode 100644
index 0000000..e0c4bc5
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.rs
@@ -0,0 +1,61 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// KnownLayout errors
+//
+
+fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              N |        N |      KL04 |
+#[derive(KnownLayout)]
+struct KL04<T: ?Sized>(u8, T);
+
+fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              Y |        N |      KL06 |
+#[derive(KnownLayout)]
+struct KL06<T: ?Sized + KnownLayout>(u8, T);
+
+fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        N |      KL12 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL12<T: ?Sized>(u8, T);
+
+fn test_kl12<T: ?Sized>(kl: &KL12<T>) {
+    assert_kl(kl)
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        Y |      KL13 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL13<T>(u8, T);
+
+fn test_kl13<T>(t: T) -> impl KnownLayout {
+    KL13(0u8, t)
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr
new file mode 100644
index 0000000..5917275
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/mid_compile_pass.stderr
@@ -0,0 +1,104 @@
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-nightly/mid_compile_pass.rs:59:26
+   |
+59 | fn test_kl13<T>(t: T) -> impl KnownLayout {
+   |                          ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13<T>: KnownLayout`
+   |
+note: required for `KL13<T>` to implement `KnownLayout`
+  --> tests/ui-nightly/mid_compile_pass.rs:55:10
+   |
+55 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+59 | fn test_kl13<T: zerocopy::KnownLayout>(t: T) -> impl KnownLayout {
+   |               +++++++++++++++++++++++
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-nightly/mid_compile_pass.rs:31:15
+   |
+30 | fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+   |              - this type parameter needs to be `Sized`
+31 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL04<T>`
+  --> tests/ui-nightly/mid_compile_pass.rs:28:8
+   |
+28 | struct KL04<T: ?Sized>(u8, T);
+   |        ^^^^
+note: required for `KL04<T>` to implement `KnownLayout`
+  --> tests/ui-nightly/mid_compile_pass.rs:27:10
+   |
+27 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-nightly/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+30 - fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+30 + fn test_kl04<T>(kl: &KL04<T>) {
+   |
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-nightly/mid_compile_pass.rs:40:15
+   |
+39 | fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+   |              - this type parameter needs to be `Sized`
+40 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL06<T>`
+  --> tests/ui-nightly/mid_compile_pass.rs:37:8
+   |
+37 | struct KL06<T: ?Sized + KnownLayout>(u8, T);
+   |        ^^^^
+note: required for `KL06<T>` to implement `KnownLayout`
+  --> tests/ui-nightly/mid_compile_pass.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-nightly/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+39 - fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+39 + fn test_kl06<T: KnownLayout>(kl: &KL06<T>) {
+   |
+
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-nightly/mid_compile_pass.rs:50:15
+   |
+50 |     assert_kl(kl)
+   |     --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12<T>: KnownLayout`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `KL12<T>` to implement `KnownLayout`
+  --> tests/ui-nightly/mid_compile_pass.rs:45:10
+   |
+45 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-nightly/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting this bound
+   |
+49 | fn test_kl12<T: ?Sized + zerocopy::KnownLayout>(kl: &KL12<T>) {
+   |                        +++++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.rs
new file mode 100644
index 0000000..c76dc7f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.rs
@@ -0,0 +1,99 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use zerocopy::KnownLayout;
+
+use self::util::AU16;
+
+fn main() {}
+
+//
+// KnownLayout errors
+//
+
+struct NotKnownLayout;
+
+struct NotKnownLayoutDst([u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              N |        N |      KL00 |
+#[derive(KnownLayout)]
+struct KL00(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              Y |        N |      KL02 |
+#[derive(KnownLayout)]
+struct KL02(u8, [u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        N |      KL08 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL08(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        Y |      KL09 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL09(NotKnownLayout, NotKnownLayout);
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1<T>(T);
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes2 {
+    foo: u8,
+    bar: AU16,
+}
+
+#[derive(AsBytes)]
+#[repr(C, packed(2))]
+struct AsBytes3 {
+    foo: u8,
+    // We'd prefer to use AU64 here, but you can't use aligned types in
+    // packed structs.
+    bar: u64,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+struct Unaligned1;
+
+#[derive(Unaligned)]
+#[repr(transparent, align(2))]
+struct Unaligned2 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+struct Unaligned3;
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4;
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5;
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.stderr
new file mode 100644
index 0000000..77e0d9e
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/struct.stderr
@@ -0,0 +1,161 @@
+error: unsupported on generic structs that are not repr(transparent) or repr(packed)
+  --> tests/ui-nightly/struct.rs:55:10
+   |
+55 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/struct.rs:80:11
+   |
+80 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/struct.rs:84:21
+   |
+84 | #[repr(transparent, align(2))]
+   |                     ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/struct.rs:90:16
+   |
+90 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/struct.rs:94:18
+   |
+94 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/struct.rs:98:8
+   |
+98 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0692]: transparent struct cannot have other repr hints
+  --> tests/ui-nightly/struct.rs:84:8
+   |
+84 | #[repr(transparent, align(2))]
+   |        ^^^^^^^^^^^  ^^^^^^^^
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/struct.rs:31:10
+   |
+31 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized`
+note: required because it appears within the type `KL00`
+  --> tests/ui-nightly/struct.rs:32:8
+   |
+32 | struct KL00(u8, NotKnownLayoutDst);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/struct.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized`
+note: required because it appears within the type `KL02`
+  --> tests/ui-nightly/struct.rs:37:8
+   |
+37 | struct KL02(u8, [u8]);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied
+  --> tests/ui-nightly/struct.rs:41:10
+   |
+41 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst`
+   |
+   = help: the following other types implement trait `KnownLayout`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied
+  --> tests/ui-nightly/struct.rs:47:10
+   |
+47 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout`
+   |
+   = help: the following other types implement trait `KnownLayout`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-nightly/struct.rs:59:10
+   |
+59 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes2, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-nightly/struct.rs:66:10
+   |
+66 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes3, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0587]: type has conflicting packed and align representation hints
+  --> tests/ui-nightly/struct.rs:91:1
+   |
+91 | struct Unaligned3;
+   | ^^^^^^^^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.rs b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.rs
new file mode 100644
index 0000000..8938e78
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.rs
@@ -0,0 +1,73 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::AU16;
+use std::mem::ManuallyDrop;
+
+fn main() {}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes1<T> {
+    foo: ManuallyDrop<T>,
+}
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes2 {
+    foo: u8,
+    bar: [u8; 2],
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+union Unaligned1 {
+    foo: i16,
+    bar: AU16,
+}
+
+// Transparent unions are unstable; see issue #60405
+// <https://github.com/rust-lang/rust/issues/60405> for more information.
+
+// #[derive(Unaligned)]
+// #[repr(transparent, align(2))]
+// union Unaligned2 {
+//     foo: u8,
+// }
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+union Unaligned3 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5 {
+    foo: u8,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.stderr
new file mode 100644
index 0000000..ae510e8
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-nightly/union.stderr
@@ -0,0 +1,51 @@
+error: unsupported on types with type parameters
+  --> tests/ui-nightly/union.rs:24:10
+   |
+24 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/union.rs:42:11
+   |
+42 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/union.rs:58:16
+   |
+58 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/union.rs:64:18
+   |
+64 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-nightly/union.rs:70:8
+   |
+70 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-nightly/union.rs:30:10
+   |
+30 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes2, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+   |
+9  + #![feature(trivial_bounds)]
+   |
+
+error[E0587]: type has conflicting packed and align representation hints
+  --> tests/ui-nightly/union.rs:59:1
+   |
+59 | union Unaligned3 {
+   | ^^^^^^^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.rs
new file mode 100644
index 0000000..2084d92
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.rs
@@ -0,0 +1,40 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use core::marker::PhantomData;
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{AsBytes, FromBytes, FromZeroes, Unaligned},
+};
+
+use self::util::NotZerocopy;
+
+fn main() {}
+
+// Test generic transparent structs
+
+#[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+#[repr(transparent)]
+struct TransparentStruct<T> {
+    inner: T,
+    _phantom: PhantomData<()>,
+}
+
+// It should be legal to derive these traits on a transparent struct, but it
+// must also ensure the traits are only implemented when the inner type
+// implements them.
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.stderr
new file mode 100644
index 0000000..57d34cb
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/derive_transparent.stderr
@@ -0,0 +1,111 @@
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-stable/derive_transparent.rs:37:18
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: FromZeroes`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `FromZeroes`
+  --> tests/ui-stable/derive_transparent.rs:27:19
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                   ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-stable/derive_transparent.rs:37:1
+   |
+37 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeroes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-stable/derive_transparent.rs:38:18
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: FromBytes`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `FromBytes`
+  --> tests/ui-stable/derive_transparent.rs:27:31
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                               ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-stable/derive_transparent.rs:38:1
+   |
+38 | assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-stable/derive_transparent.rs:39:18
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: AsBytes`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `AsBytes`
+  --> tests/ui-stable/derive_transparent.rs:27:10
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |          ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-stable/derive_transparent.rs:39:1
+   |
+39 | assert_impl_all!(TransparentStruct<NotZerocopy>: AsBytes);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: Unaligned` is not satisfied
+  --> tests/ui-stable/derive_transparent.rs:40:18
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `NotZerocopy`, which is required by `TransparentStruct<NotZerocopy>: Unaligned`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required for `TransparentStruct<NotZerocopy>` to implement `Unaligned`
+  --> tests/ui-stable/derive_transparent.rs:27:42
+   |
+27 | #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+   |                                          ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::{closure#0}::assert_impl_all`
+  --> tests/ui-stable/derive_transparent.rs:40:1
+   |
+40 | assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
+   = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.rs
new file mode 100644
index 0000000..31d5679
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.rs
@@ -0,0 +1,194 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+//
+// Generic errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr("foo")]
+enum Generic1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(foo)]
+enum Generic2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(transparent)]
+enum Generic3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u8, u16)]
+enum Generic4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+enum Generic5 {
+    A,
+}
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+enum FromZeroes1 {
+    A(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes2 {
+    A,
+    B(u8),
+}
+
+#[derive(FromZeroes)]
+enum FromZeroes3 {
+    A = 1,
+    B,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(C)]
+enum FromBytes1 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(usize)]
+enum FromBytes2 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(isize)]
+enum FromBytes3 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u32)]
+enum FromBytes4 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i32)]
+enum FromBytes5 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(u64)]
+enum FromBytes6 {
+    A,
+}
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(i64)]
+enum FromBytes7 {
+    A,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+enum Unaligned1 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u16)]
+enum Unaligned2 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i16)]
+enum Unaligned3 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u32)]
+enum Unaligned4 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i32)]
+enum Unaligned5 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u64)]
+enum Unaligned6 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i64)]
+enum Unaligned7 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(usize)]
+enum Unaligned8 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(isize)]
+enum Unaligned9 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(u8, align(2))]
+enum Unaligned10 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(i8, align(2))]
+enum Unaligned11 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+enum Unaligned12 {
+    A,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+enum Unaligned13 {
+    A,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.stderr
new file mode 100644
index 0000000..a47ce9c
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum.stderr
@@ -0,0 +1,201 @@
+error: unrecognized representation hint
+  --> tests/ui-stable/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error: unrecognized representation hint
+  --> tests/ui-stable/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+
+error: unsupported representation for deriving FromBytes, AsBytes, or Unaligned on an enum
+  --> tests/ui-stable/enum.rs:31:8
+   |
+31 | #[repr(transparent)]
+   |        ^^^^^^^^^^^
+
+error: conflicting representation hints
+  --> tests/ui-stable/enum.rs:37:1
+   |
+37 | #[repr(u8, u16)]
+   | ^
+
+error: must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout
+  --> tests/ui-stable/enum.rs:42:22
+   |
+42 | #[derive(FromZeroes, FromBytes)]
+   |                      ^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-stable/enum.rs:52:1
+   |
+52 | / enum FromZeroes1 {
+53 | |     A(u8),
+54 | | }
+   | |_^
+
+error: only C-like enums can implement FromZeroes
+  --> tests/ui-stable/enum.rs:57:1
+   |
+57 | / enum FromZeroes2 {
+58 | |     A,
+59 | |     B(u8),
+60 | | }
+   | |_^
+
+error: FromZeroes only supported on enums with a variant that has a discriminant of `0`
+  --> tests/ui-stable/enum.rs:63:1
+   |
+63 | / enum FromZeroes3 {
+64 | |     A = 1,
+65 | |     B,
+66 | | }
+   | |_^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-stable/enum.rs:73:8
+   |
+73 | #[repr(C)]
+   |        ^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-stable/enum.rs:79:8
+   |
+79 | #[repr(usize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-stable/enum.rs:85:8
+   |
+85 | #[repr(isize)]
+   |        ^^^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-stable/enum.rs:91:8
+   |
+91 | #[repr(u32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+  --> tests/ui-stable/enum.rs:97:8
+   |
+97 | #[repr(i32)]
+   |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-stable/enum.rs:103:8
+    |
+103 | #[repr(u64)]
+    |        ^^^
+
+error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
+   --> tests/ui-stable/enum.rs:109:8
+    |
+109 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:119:8
+    |
+119 | #[repr(C)]
+    |        ^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:125:8
+    |
+125 | #[repr(u16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:131:8
+    |
+131 | #[repr(i16)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:137:8
+    |
+137 | #[repr(u32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:143:8
+    |
+143 | #[repr(i32)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:149:8
+    |
+149 | #[repr(u64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:155:8
+    |
+155 | #[repr(i64)]
+    |        ^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:161:8
+    |
+161 | #[repr(usize)]
+    |        ^^^^^
+
+error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
+   --> tests/ui-stable/enum.rs:167:8
+    |
+167 | #[repr(isize)]
+    |        ^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-stable/enum.rs:173:12
+    |
+173 | #[repr(u8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-stable/enum.rs:179:12
+    |
+179 | #[repr(i8, align(2))]
+    |            ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-stable/enum.rs:185:18
+    |
+185 | #[repr(align(1), align(2))]
+    |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+   --> tests/ui-stable/enum.rs:191:8
+    |
+191 | #[repr(align(2), align(4))]
+    |        ^^^^^^^^
+
+error[E0565]: meta item in `repr` must be an identifier
+  --> tests/ui-stable/enum.rs:19:8
+   |
+19 | #[repr("foo")]
+   |        ^^^^^
+
+error[E0552]: unrecognized representation hint
+  --> tests/ui-stable/enum.rs:25:8
+   |
+25 | #[repr(foo)]
+   |        ^^^
+   |
+   = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0566]: conflicting representation hints
+  --> tests/ui-stable/enum.rs:37:8
+   |
+37 | #[repr(u8, u16)]
+   |        ^^  ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>
+   = note: `#[deny(conflicting_repr_hints)]` on by default
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs
new file mode 100644
index 0000000..1b1bed3
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.rs
@@ -0,0 +1,272 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+#[derive(FromBytes)]
+#[repr(u8)]
+enum Foo {
+    Variant0,
+    Variant1,
+    Variant2,
+    Variant3,
+    Variant4,
+    Variant5,
+    Variant6,
+    Variant7,
+    Variant8,
+    Variant9,
+    Variant10,
+    Variant11,
+    Variant12,
+    Variant13,
+    Variant14,
+    Variant15,
+    Variant16,
+    Variant17,
+    Variant18,
+    Variant19,
+    Variant20,
+    Variant21,
+    Variant22,
+    Variant23,
+    Variant24,
+    Variant25,
+    Variant26,
+    Variant27,
+    Variant28,
+    Variant29,
+    Variant30,
+    Variant31,
+    Variant32,
+    Variant33,
+    Variant34,
+    Variant35,
+    Variant36,
+    Variant37,
+    Variant38,
+    Variant39,
+    Variant40,
+    Variant41,
+    Variant42,
+    Variant43,
+    Variant44,
+    Variant45,
+    Variant46,
+    Variant47,
+    Variant48,
+    Variant49,
+    Variant50,
+    Variant51,
+    Variant52,
+    Variant53,
+    Variant54,
+    Variant55,
+    Variant56,
+    Variant57,
+    Variant58,
+    Variant59,
+    Variant60,
+    Variant61,
+    Variant62,
+    Variant63,
+    Variant64,
+    Variant65,
+    Variant66,
+    Variant67,
+    Variant68,
+    Variant69,
+    Variant70,
+    Variant71,
+    Variant72,
+    Variant73,
+    Variant74,
+    Variant75,
+    Variant76,
+    Variant77,
+    Variant78,
+    Variant79,
+    Variant80,
+    Variant81,
+    Variant82,
+    Variant83,
+    Variant84,
+    Variant85,
+    Variant86,
+    Variant87,
+    Variant88,
+    Variant89,
+    Variant90,
+    Variant91,
+    Variant92,
+    Variant93,
+    Variant94,
+    Variant95,
+    Variant96,
+    Variant97,
+    Variant98,
+    Variant99,
+    Variant100,
+    Variant101,
+    Variant102,
+    Variant103,
+    Variant104,
+    Variant105,
+    Variant106,
+    Variant107,
+    Variant108,
+    Variant109,
+    Variant110,
+    Variant111,
+    Variant112,
+    Variant113,
+    Variant114,
+    Variant115,
+    Variant116,
+    Variant117,
+    Variant118,
+    Variant119,
+    Variant120,
+    Variant121,
+    Variant122,
+    Variant123,
+    Variant124,
+    Variant125,
+    Variant126,
+    Variant127,
+    Variant128,
+    Variant129,
+    Variant130,
+    Variant131,
+    Variant132,
+    Variant133,
+    Variant134,
+    Variant135,
+    Variant136,
+    Variant137,
+    Variant138,
+    Variant139,
+    Variant140,
+    Variant141,
+    Variant142,
+    Variant143,
+    Variant144,
+    Variant145,
+    Variant146,
+    Variant147,
+    Variant148,
+    Variant149,
+    Variant150,
+    Variant151,
+    Variant152,
+    Variant153,
+    Variant154,
+    Variant155,
+    Variant156,
+    Variant157,
+    Variant158,
+    Variant159,
+    Variant160,
+    Variant161,
+    Variant162,
+    Variant163,
+    Variant164,
+    Variant165,
+    Variant166,
+    Variant167,
+    Variant168,
+    Variant169,
+    Variant170,
+    Variant171,
+    Variant172,
+    Variant173,
+    Variant174,
+    Variant175,
+    Variant176,
+    Variant177,
+    Variant178,
+    Variant179,
+    Variant180,
+    Variant181,
+    Variant182,
+    Variant183,
+    Variant184,
+    Variant185,
+    Variant186,
+    Variant187,
+    Variant188,
+    Variant189,
+    Variant190,
+    Variant191,
+    Variant192,
+    Variant193,
+    Variant194,
+    Variant195,
+    Variant196,
+    Variant197,
+    Variant198,
+    Variant199,
+    Variant200,
+    Variant201,
+    Variant202,
+    Variant203,
+    Variant204,
+    Variant205,
+    Variant206,
+    Variant207,
+    Variant208,
+    Variant209,
+    Variant210,
+    Variant211,
+    Variant212,
+    Variant213,
+    Variant214,
+    Variant215,
+    Variant216,
+    Variant217,
+    Variant218,
+    Variant219,
+    Variant220,
+    Variant221,
+    Variant222,
+    Variant223,
+    Variant224,
+    Variant225,
+    Variant226,
+    Variant227,
+    Variant228,
+    Variant229,
+    Variant230,
+    Variant231,
+    Variant232,
+    Variant233,
+    Variant234,
+    Variant235,
+    Variant236,
+    Variant237,
+    Variant238,
+    Variant239,
+    Variant240,
+    Variant241,
+    Variant242,
+    Variant243,
+    Variant244,
+    Variant245,
+    Variant246,
+    Variant247,
+    Variant248,
+    Variant249,
+    Variant250,
+    Variant251,
+    Variant252,
+    Variant253,
+    Variant254,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr
new file mode 100644
index 0000000..5edbabc
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/enum_from_bytes_u8_too_few.stderr
@@ -0,0 +1,11 @@
+error: FromBytes only supported on repr(u8) enum with 256 variants
+   --> tests/ui-stable/enum_from_bytes_u8_too_few.rs:15:1
+    |
+15  | / #[repr(u8)]
+16  | | enum Foo {
+17  | |     Variant0,
+18  | |     Variant1,
+...   |
+271 | |     Variant254,
+272 | | }
+    | |_^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.rs
new file mode 100644
index 0000000..cd65a6e
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::{NotZerocopy, AU16};
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// FromZeroes errors
+//
+
+#[derive(FromZeroes)]
+struct FromZeroes1 {
+    value: NotZerocopy,
+}
+
+//
+// FromBytes errors
+//
+
+#[derive(FromBytes)]
+struct FromBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1 {
+    value: NotZerocopy,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned1 {
+    aligned: AU16,
+}
+
+// This specifically tests a bug we had in an old version of the code in which
+// the trait bound would only be enforced for the first field's type.
+#[derive(Unaligned)]
+#[repr(C)]
+struct Unaligned2 {
+    unaligned: u8,
+    aligned: AU16,
+}
+
+#[derive(Unaligned)]
+#[repr(transparent)]
+struct Unaligned3 {
+    aligned: AU16,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr
new file mode 100644
index 0000000..0c66ae5
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr
@@ -0,0 +1,144 @@
+warning: unused import: `zerocopy::KnownLayout`
+  --> tests/ui-stable/late_compile_pass.rs:16:5
+   |
+16 | use zerocopy::KnownLayout;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unused_imports)]` on by default
+
+error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:28:10
+   |
+28 | #[derive(FromZeroes)]
+   |          ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             FromZeroes1
+             I128<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             FromBytes1
+             I128<O>
+             I16<O>
+             I32<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:37:10
+   |
+37 | #[derive(FromBytes)]
+   |          ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1`
+   |
+   = help: the following other types implement trait `FromZeroes`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             FromZeroes1
+             I128<O>
+           and $N others
+note: required by a bound in `FromBytes`
+  --> $WORKSPACE/src/lib.rs
+   |
+   | pub unsafe trait FromBytes: FromZeroes {
+   |                             ^^^^^^^^^^ required by this bound in `FromBytes`
+   = note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:46:10
+   |
+46 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             AsBytes1
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:56:10
+   |
+56 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:64:10
+   |
+64 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
+  --> tests/ui-stable/late_compile_pass.rs:71:10
+   |
+71 | #[derive(Unaligned)]
+   |          ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
+   |
+   = help: the following other types implement trait `Unaligned`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs
new file mode 100644
index 0000000..e0c4bc5
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.rs
@@ -0,0 +1,61 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::KnownLayout;
+
+fn main() {}
+
+// These tests cause errors which are generated by a later compilation pass than
+// the other errors we generate, and so if they're compiled in the same file,
+// the compiler will never get to that pass, and so we won't get the errors.
+
+//
+// KnownLayout errors
+//
+
+fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              N |        N |      KL04 |
+#[derive(KnownLayout)]
+struct KL04<T: ?Sized>(u8, T);
+
+fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        Y |              Y |        N |      KL06 |
+#[derive(KnownLayout)]
+struct KL06<T: ?Sized + KnownLayout>(u8, T);
+
+fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+    assert_kl(kl);
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        N |      KL12 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL12<T: ?Sized>(u8, T);
+
+fn test_kl12<T: ?Sized>(kl: &KL12<T>) {
+    assert_kl(kl)
+}
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        Y |              N |        Y |      KL13 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL13<T>(u8, T);
+
+fn test_kl13<T>(t: T) -> impl KnownLayout {
+    KL13(0u8, t)
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr
new file mode 100644
index 0000000..ee7dcb9
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/mid_compile_pass.stderr
@@ -0,0 +1,104 @@
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-stable/mid_compile_pass.rs:59:26
+   |
+59 | fn test_kl13<T>(t: T) -> impl KnownLayout {
+   |                          ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL13<T>: KnownLayout`
+   |
+note: required for `KL13<T>` to implement `KnownLayout`
+  --> tests/ui-stable/mid_compile_pass.rs:55:10
+   |
+55 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+59 | fn test_kl13<T: zerocopy::KnownLayout>(t: T) -> impl KnownLayout {
+   |               +++++++++++++++++++++++
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-stable/mid_compile_pass.rs:31:15
+   |
+30 | fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+   |              - this type parameter needs to be `Sized`
+31 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL04<T>`
+  --> tests/ui-stable/mid_compile_pass.rs:28:8
+   |
+28 | struct KL04<T: ?Sized>(u8, T);
+   |        ^^^^
+note: required for `KL04<T>` to implement `KnownLayout`
+  --> tests/ui-stable/mid_compile_pass.rs:27:10
+   |
+27 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-stable/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+30 - fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
+30 + fn test_kl04<T>(kl: &KL04<T>) {
+   |
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> tests/ui-stable/mid_compile_pass.rs:40:15
+   |
+39 | fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+   |              - this type parameter needs to be `Sized`
+40 |     assert_kl(kl);
+   |     --------- ^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `KL06<T>`
+  --> tests/ui-stable/mid_compile_pass.rs:37:8
+   |
+37 | struct KL06<T: ?Sized + KnownLayout>(u8, T);
+   |        ^^^^
+note: required for `KL06<T>` to implement `KnownLayout`
+  --> tests/ui-stable/mid_compile_pass.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-stable/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+39 - fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
+39 + fn test_kl06<T: KnownLayout>(kl: &KL06<T>) {
+   |
+
+error[E0277]: the trait bound `T: KnownLayout` is not satisfied
+  --> tests/ui-stable/mid_compile_pass.rs:50:15
+   |
+50 |     assert_kl(kl)
+   |     --------- ^^ the trait `KnownLayout` is not implemented for `T`, which is required by `KL12<T>: KnownLayout`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `KL12<T>` to implement `KnownLayout`
+  --> tests/ui-stable/mid_compile_pass.rs:45:10
+   |
+45 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `assert_kl`
+  --> tests/ui-stable/mid_compile_pass.rs:23:26
+   |
+23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+   |                          ^^^^^^^^^^^ required by this bound in `assert_kl`
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting this bound
+   |
+49 | fn test_kl12<T: ?Sized + zerocopy::KnownLayout>(kl: &KL12<T>) {
+   |                        +++++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.rs
new file mode 100644
index 0000000..c76dc7f
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.rs
@@ -0,0 +1,99 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use zerocopy::KnownLayout;
+
+use self::util::AU16;
+
+fn main() {}
+
+//
+// KnownLayout errors
+//
+
+struct NotKnownLayout;
+
+struct NotKnownLayoutDst([u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              N |        N |      KL00 |
+#[derive(KnownLayout)]
+struct KL00(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          N |        N |              Y |        N |      KL02 |
+#[derive(KnownLayout)]
+struct KL02(u8, [u8]);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        N |      KL08 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL08(u8, NotKnownLayoutDst);
+
+// | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+// |          Y |        N |              N |        Y |      KL09 |
+#[derive(KnownLayout)]
+#[repr(C)]
+struct KL09(NotKnownLayout, NotKnownLayout);
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes1<T>(T);
+
+#[derive(AsBytes)]
+#[repr(C)]
+struct AsBytes2 {
+    foo: u8,
+    bar: AU16,
+}
+
+#[derive(AsBytes)]
+#[repr(C, packed(2))]
+struct AsBytes3 {
+    foo: u8,
+    // We'd prefer to use AU64 here, but you can't use aligned types in
+    // packed structs.
+    bar: u64,
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+struct Unaligned1;
+
+#[derive(Unaligned)]
+#[repr(transparent, align(2))]
+struct Unaligned2 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+struct Unaligned3;
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4;
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5;
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.stderr
new file mode 100644
index 0000000..c1e95af
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/struct.stderr
@@ -0,0 +1,137 @@
+error: unsupported on generic structs that are not repr(transparent) or repr(packed)
+  --> tests/ui-stable/struct.rs:55:10
+   |
+55 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/struct.rs:80:11
+   |
+80 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/struct.rs:84:21
+   |
+84 | #[repr(transparent, align(2))]
+   |                     ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/struct.rs:90:16
+   |
+90 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/struct.rs:94:18
+   |
+94 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/struct.rs:98:8
+   |
+98 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0692]: transparent struct cannot have other repr hints
+  --> tests/ui-stable/struct.rs:84:8
+   |
+84 | #[repr(transparent, align(2))]
+   |        ^^^^^^^^^^^  ^^^^^^^^
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/struct.rs:31:10
+   |
+31 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL00`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL00: Sized`
+note: required because it appears within the type `KL00`
+  --> tests/ui-stable/struct.rs:32:8
+   |
+32 | struct KL00(u8, NotKnownLayoutDst);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/struct.rs:36:10
+   |
+36 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `KL02`, the trait `Sized` is not implemented for `[u8]`, which is required by `KL02: Sized`
+note: required because it appears within the type `KL02`
+  --> tests/ui-stable/struct.rs:37:8
+   |
+37 | struct KL02(u8, [u8]);
+   |        ^^^^
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotKnownLayoutDst: KnownLayout` is not satisfied
+  --> tests/ui-stable/struct.rs:41:10
+   |
+41 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayoutDst`
+   |
+   = help: the following other types implement trait `KnownLayout`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotKnownLayout: KnownLayout` is not satisfied
+  --> tests/ui-stable/struct.rs:47:10
+   |
+47 | #[derive(KnownLayout)]
+   |          ^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `NotKnownLayout`
+   |
+   = help: the following other types implement trait `KnownLayout`:
+             ()
+             *const T
+             *mut T
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+           and $N others
+   = help: see issue #48214
+   = note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-stable/struct.rs:59:10
+   |
+59 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes2, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-stable/struct.rs:66:10
+   |
+66 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes3, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0587]: type has conflicting packed and align representation hints
+  --> tests/ui-stable/struct.rs:91:1
+   |
+91 | struct Unaligned3;
+   | ^^^^^^^^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.rs b/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.rs
new file mode 100644
index 0000000..8938e78
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.rs
@@ -0,0 +1,73 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+extern crate zerocopy;
+
+#[path = "../util.rs"]
+mod util;
+
+use self::util::AU16;
+use std::mem::ManuallyDrop;
+
+fn main() {}
+
+//
+// AsBytes errors
+//
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes1<T> {
+    foo: ManuallyDrop<T>,
+}
+
+#[derive(AsBytes)]
+#[repr(C)]
+union AsBytes2 {
+    foo: u8,
+    bar: [u8; 2],
+}
+
+//
+// Unaligned errors
+//
+
+#[derive(Unaligned)]
+#[repr(C, align(2))]
+union Unaligned1 {
+    foo: i16,
+    bar: AU16,
+}
+
+// Transparent unions are unstable; see issue #60405
+// <https://github.com/rust-lang/rust/issues/60405> for more information.
+
+// #[derive(Unaligned)]
+// #[repr(transparent, align(2))]
+// union Unaligned2 {
+//     foo: u8,
+// }
+
+#[derive(Unaligned)]
+#[repr(packed, align(2))]
+union Unaligned3 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(1), align(2))]
+struct Unaligned4 {
+    foo: u8,
+}
+
+#[derive(Unaligned)]
+#[repr(align(2), align(4))]
+struct Unaligned5 {
+    foo: u8,
+}
diff --git a/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.stderr b/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.stderr
new file mode 100644
index 0000000..f7d6953
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/ui-stable/union.stderr
@@ -0,0 +1,47 @@
+error: unsupported on types with type parameters
+  --> tests/ui-stable/union.rs:24:10
+   |
+24 | #[derive(AsBytes)]
+   |          ^^^^^^^
+   |
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/union.rs:42:11
+   |
+42 | #[repr(C, align(2))]
+   |           ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/union.rs:58:16
+   |
+58 | #[repr(packed, align(2))]
+   |                ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/union.rs:64:18
+   |
+64 | #[repr(align(1), align(2))]
+   |                  ^^^^^^^^
+
+error: cannot derive Unaligned with repr(align(N > 1))
+  --> tests/ui-stable/union.rs:70:8
+   |
+70 | #[repr(align(2), align(4))]
+   |        ^^^^^^^^
+
+error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is not satisfied
+  --> tests/ui-stable/union.rs:30:10
+   |
+30 | #[derive(AsBytes)]
+   |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes2, true>`
+   |
+   = help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes2, true>`
+   = help: see issue #48214
+   = note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0587]: type has conflicting packed and align representation hints
+  --> tests/ui-stable/union.rs:59:1
+   |
+59 | union Unaligned3 {
+   | ^^^^^^^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy-derive/tests/union_as_bytes.rs b/extra_versions/crates/zerocopy-derive/tests/union_as_bytes.rs
new file mode 100644
index 0000000..84f5181
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/union_as_bytes.rs
@@ -0,0 +1,75 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::AsBytes};
+
+// A union is `AsBytes` if:
+// - all fields are `AsBytes`
+// - `repr(C)` or `repr(transparent)` and
+//   - no padding (size of union equals size of each field type)
+// - `repr(packed)`
+
+#[derive(AsBytes, Clone, Copy)]
+#[repr(C)]
+union CZst {
+    a: (),
+}
+
+assert_impl_all!(CZst: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C)]
+union C {
+    a: u8,
+    b: u8,
+}
+
+assert_impl_all!(C: AsBytes);
+
+// Transparent unions are unstable; see issue #60405
+// <https://github.com/rust-lang/rust/issues/60405> for more information.
+
+// #[derive(AsBytes)]
+// #[repr(transparent)]
+// union Transparent {
+//     a: u8,
+//     b: CZst,
+// }
+
+// is_as_bytes!(Transparent);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+union CZstPacked {
+    a: (),
+}
+
+assert_impl_all!(CZstPacked: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+union CPacked {
+    a: u8,
+    b: i8,
+}
+
+assert_impl_all!(CPacked: AsBytes);
+
+#[derive(AsBytes)]
+#[repr(C, packed)]
+union CMultibytePacked {
+    a: i32,
+    b: u32,
+    c: f32,
+}
+
+assert_impl_all!(CMultibytePacked: AsBytes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/union_from_bytes.rs b/extra_versions/crates/zerocopy-derive/tests/union_from_bytes.rs
new file mode 100644
index 0000000..4635735
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/union_from_bytes.rs
@@ -0,0 +1,72 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {
+    static_assertions::assert_impl_all,
+    zerocopy::{FromBytes, FromZeroes},
+};
+
+// A union is `FromBytes` if:
+// - all fields are `FromBytes`
+
+#[derive(Clone, Copy, FromZeroes, FromBytes)]
+union Zst {
+    a: (),
+}
+
+assert_impl_all!(Zst: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+union One {
+    a: u8,
+}
+
+assert_impl_all!(One: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+union Two {
+    a: u8,
+    b: Zst,
+}
+
+assert_impl_all!(Two: FromBytes);
+
+#[derive(FromZeroes, FromBytes)]
+union TypeParams<'a, T: Copy, I: Iterator>
+where
+    I::Item: Copy,
+{
+    a: T,
+    c: I::Item,
+    d: u8,
+    e: PhantomData<&'a [u8]>,
+    f: PhantomData<&'static str>,
+    g: PhantomData<String>,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromBytes);
+
+// Deriving `FromBytes` should work if the union has bounded parameters.
+
+#[derive(FromZeroes, FromBytes)]
+#[repr(C)]
+union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromBytes>
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + Copy + FromBytes,
+{
+    a: [T; N],
+    b: PhantomData<&'a &'b ()>,
+}
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromBytes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/union_from_zeroes.rs b/extra_versions/crates/zerocopy-derive/tests/union_from_zeroes.rs
new file mode 100644
index 0000000..935fc15
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/union_from_zeroes.rs
@@ -0,0 +1,72 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+#[macro_use]
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::FromZeroes};
+
+// A union is `FromZeroes` if:
+// - all fields are `FromZeroes`
+
+#[derive(Clone, Copy, FromZeroes)]
+union Zst {
+    a: (),
+}
+
+assert_impl_all!(Zst: FromZeroes);
+
+#[derive(FromZeroes)]
+union One {
+    a: bool,
+}
+
+assert_impl_all!(One: FromZeroes);
+
+#[derive(FromZeroes)]
+union Two {
+    a: bool,
+    b: Zst,
+}
+
+assert_impl_all!(Two: FromZeroes);
+
+#[derive(FromZeroes)]
+union TypeParams<'a, T: Copy, I: Iterator>
+where
+    I::Item: Copy,
+{
+    a: T,
+    c: I::Item,
+    d: u8,
+    e: PhantomData<&'a [u8]>,
+    f: PhantomData<&'static str>,
+    g: PhantomData<String>,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: FromZeroes);
+
+// Deriving `FromZeroes` should work if the union has bounded parameters.
+
+#[derive(FromZeroes)]
+#[repr(C)]
+union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + FromZeroes>
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + Copy + FromZeroes,
+{
+    a: [T; N],
+    b: PhantomData<&'a &'b ()>,
+}
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: FromZeroes);
diff --git a/extra_versions/crates/zerocopy-derive/tests/union_known_layout.rs b/extra_versions/crates/zerocopy-derive/tests/union_known_layout.rs
new file mode 100644
index 0000000..337ab4a
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/union_known_layout.rs
@@ -0,0 +1,65 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![allow(warnings)]
+
+#[macro_use]
+mod util;
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::KnownLayout};
+
+#[derive(Clone, Copy, KnownLayout)]
+union Zst {
+    a: (),
+}
+
+assert_impl_all!(Zst: KnownLayout);
+
+#[derive(KnownLayout)]
+union One {
+    a: bool,
+}
+
+assert_impl_all!(One: KnownLayout);
+
+#[derive(KnownLayout)]
+union Two {
+    a: bool,
+    b: Zst,
+}
+
+assert_impl_all!(Two: KnownLayout);
+
+#[derive(KnownLayout)]
+union TypeParams<'a, T: Copy, I: Iterator>
+where
+    I::Item: Copy,
+{
+    a: T,
+    c: I::Item,
+    d: u8,
+    e: PhantomData<&'a [u8]>,
+    f: PhantomData<&'static str>,
+    g: PhantomData<String>,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: KnownLayout);
+
+// Deriving `KnownLayout` should work if the union has bounded parameters.
+
+#[derive(KnownLayout)]
+#[repr(C)]
+union WithParams<'a: 'b, 'b: 'a, const N: usize, T: 'a + 'b + KnownLayout>
+where
+    'a: 'b,
+    'b: 'a,
+    T: 'a + 'b + Copy + KnownLayout,
+{
+    a: [T; N],
+    b: PhantomData<&'a &'b ()>,
+}
+
+assert_impl_all!(WithParams<'static, 'static, 42, u8>: KnownLayout);
diff --git a/extra_versions/crates/zerocopy-derive/tests/union_unaligned.rs b/extra_versions/crates/zerocopy-derive/tests/union_unaligned.rs
new file mode 100644
index 0000000..5ba3ac7
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/union_unaligned.rs
@@ -0,0 +1,77 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#![allow(warnings)]
+
+use std::{marker::PhantomData, option::IntoIter};
+
+use {static_assertions::assert_impl_all, zerocopy::Unaligned};
+
+// A union is `Unaligned` if:
+// - `repr(align)` is no more than 1 and either
+//   - `repr(C)` or `repr(transparent)` and
+//     - all fields `Unaligned`
+//   - `repr(packed)`
+
+#[derive(Unaligned)]
+#[repr(C)]
+union Foo {
+    a: u8,
+}
+
+assert_impl_all!(Foo: Unaligned);
+
+// Transparent unions are unstable; see issue #60405
+// <https://github.com/rust-lang/rust/issues/60405> for more information.
+
+// #[derive(Unaligned)]
+// #[repr(transparent)]
+// union Bar {
+//     a: u8,
+// }
+
+// is_unaligned!(Bar);
+
+#[derive(Unaligned)]
+#[repr(packed)]
+union Baz {
+    // NOTE: The `u16` type is not guaranteed to have alignment 2, although it
+    // does on many platforms. However, to fix this would require a custom type
+    // with a `#[repr(align(2))]` attribute, and `#[repr(packed)]` types are not
+    // allowed to transitively contain `#[repr(align(...))]` types. Thus, we
+    // have no choice but to use `u16` here. Luckily, these tests run in CI on
+    // platforms on which `u16` has alignment 2, so this isn't that big of a
+    // deal.
+    a: u16,
+}
+
+assert_impl_all!(Baz: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(C, align(1))]
+union FooAlign {
+    a: u8,
+}
+
+assert_impl_all!(FooAlign: Unaligned);
+
+#[derive(Unaligned)]
+#[repr(C)]
+union TypeParams<'a, T: Copy, I: Iterator>
+where
+    I::Item: Copy,
+{
+    a: T,
+    c: I::Item,
+    d: u8,
+    e: PhantomData<&'a [u8]>,
+    f: PhantomData<&'static str>,
+    g: PhantomData<String>,
+}
+
+assert_impl_all!(TypeParams<'static, (), IntoIter<()>>: Unaligned);
diff --git a/extra_versions/crates/zerocopy-derive/tests/util.rs b/extra_versions/crates/zerocopy-derive/tests/util.rs
new file mode 100644
index 0000000..a8656fb
--- /dev/null
+++ b/extra_versions/crates/zerocopy-derive/tests/util.rs
@@ -0,0 +1,20 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use zerocopy::{AsBytes, FromBytes, FromZeroes, KnownLayout};
+
+/// A type that doesn't implement any zerocopy traits.
+pub struct NotZerocopy<T = ()>(T);
+
+/// A `u16` with alignment 2.
+///
+/// Though `u16` has alignment 2 on some platforms, it's not guaranteed. By
+/// contrast, `AU16` is guaranteed to have alignment 2.
+#[derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Copy, Clone)]
+#[repr(C, align(2))]
+pub struct AU16(u16);
diff --git a/extra_versions/crates/zerocopy/.cargo-checksum.json b/extra_versions/crates/zerocopy/.cargo-checksum.json
new file mode 100644
index 0000000..0ce7b1a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CONTRIBUTING.md":"47968395d4bee21ffd1f4e665625ba6c89b841a71dc92d0cac432aafbcbfe027","Cargo.toml":"47af3f175210cf5fc335912d94cbbb0ecf38219ba02524e1941fab092cb84a12","INTERNAL.md":"d6f3929776cd6b195d926dda36b7db287f92fa17ed8dabb0c9c12eb6f945bd61","LICENSE-APACHE":"9d185ac6703c4b0453974c0d85e9eee43e6941009296bb1f5eb0b54e2329e9f3","LICENSE-BSD":"83c1763356e822adde0a2cae748d938a73fdc263849ccff6b27776dff213bd32","LICENSE-MIT":"1a2f5c12ddc934d58956aa5dbdd3255fe55fd957633ab7d0d39e4f0daa73f7df","POLICIES.md":"49c64d06d94b4f1d339f518d25a4fd379fc0851189f1e0b2413725708a61a409","README.md":"a2a01b58f7344a1a03b314d545d221e1a22642071d2067ebefbeb0d1c63a27d0","cargo.sh":"ea53cc247d35243fbe161024890f7c2f855688b8fd26b7244df5ae999ba99bd2","clippy.toml":"df67a6131fff2fe52309e797d2dfad080fc8cbdfcb1baa7f14415b3e397c291c","generate-readme.sh":"0b86377c6ca87971154b8f461e71d72727ecb65e550d2f96729d8949e5264155","rustfmt.toml":"33a21d11175200d203fcdb803c61a24fc461661bf8a2de7c9189af7ecee123c2","src/byteorder.rs":"b84a7ff52d88fdc51c7c660a8e8afb66490551c67aa6f46bf0afcbeb392d2e92","src/lib.rs":"eb5033d1f2f3d5314625bc63353b1d105cb414d4bc68edf8700b401e4055d669","src/macro_util.rs":"de8d86a49ae79f6995a13d735f09421e5e0676494d00a5532fcae91f357c2294","src/macros.rs":"cfb3970b51d6d2895a16ca716bace7497a723923bc540e987ba911aaed94fa86","src/post_monomorphization_compile_fail_tests.rs":"6f20b9ddb9d8c2573f2f0c18f58998b9207e588190586891f48b00570f7d4623","src/third_party/rust/LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","src/third_party/rust/LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/third_party/rust/README.fuchsia":"5dc26ec369c273eb99679b43c5de4c41c82797e8800c3926c4c76912e9596ecf","src/third_party/rust/layout.rs":"bf602961483f1ed0266602c00bc31345da38f4601954ed4a673f26d7ae8199b9","src/util.rs":"6ddd878212c7c3bd924f506fce4a713ebd75c5828182c1b5eff0d94c36895134","src/wrappers.rs":"53648beaef9926efb8348a1b3956526b9f9dad725dca7051f2033a833957b3b3","testdata/include_value/data":"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589","tests/trybuild.rs":"8b77ed684725d2e99fd7806d8f361cd2495b388cc463be3ff2fae25bcbe34c56","tests/ui-msrv/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-msrv/include_value_not_from_bytes.stderr":"57d634cea8f0906b08e7eea056d09b02364f2a656623116c29fdc706b5393926","tests/ui-msrv/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-msrv/include_value_wrong_size.stderr":"40bcc6c0172b530cda18bf60d35550e219254a71c0a1e4b16417b17db6d18829","tests/ui-msrv/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-msrv/invalid-impls/invalid-impls.stderr":"ddc7a15d675f91b8b838c5c1b8e0d3973d981b11ce956e0f50d4880f0ff0e408","tests/ui-msrv/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-msrv/max-align.stderr":"38775aa2a8bc035eedbc57ab0081c865b804d9a7fc5200ec425210fdea6a69d1","tests/ui-msrv/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-msrv/transmute-dst-not-frombytes.stderr":"537111d0377c9a255bb9cd43fa12646a901f0b8cf6b1fb5842fb5f0d41ea86e8","tests/ui-msrv/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-msrv/transmute-mut-alignment-increase.stderr":"9e879881032ab5ba28f8cc6a240bf96150c4a7fb3e55b1de0c808dc5e0b1179d","tests/ui-msrv/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-msrv/transmute-mut-const.stderr":"3c8dcb20b8cffd73f3b330b0199c5912ff015b51fce6d3acf684e388abb70a9c","tests/ui-msrv/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-msrv/transmute-mut-dst-generic.stderr":"d19ae09a138d21aa64da708da85fd09b9b98a70c76cf397f5cbe7866ccbddbed","tests/ui-msrv/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr":"1cca08728f4b93b78757224420090f4ec0a2014043e9b1d86ffafe9fcc8f1faa","tests/ui-msrv/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr":"fd4a28b880eebd3d4f4b1f0388a26b372b07fd8186979970e2ea881379bf007b","tests/ui-msrv/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr":"fd9e4c396c995be82b4bda2a28565f5d427d9733ae85f56cfb3922b1130fa06a","tests/ui-msrv/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-msrv/transmute-mut-dst-unsized.stderr":"b0c443b692859195ade80fb3650d51b4a01c2dd8b523322db84acfc3845b154d","tests/ui-msrv/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-msrv/transmute-mut-illegal-lifetime.stderr":"ff5965b190242ce05735d7c072c11565c5bd8609261c83dd06396ae8416dfbaa","tests/ui-msrv/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-msrv/transmute-mut-size-decrease.stderr":"ae0c86cfbd85107ea908218c5389218a64a46ccf53a0bc553b9c17b48f475e0f","tests/ui-msrv/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-msrv/transmute-mut-size-increase.stderr":"d8f4c9f85c59cf24f88e08b3e67796d1218a512e0082100bb63fe38a69186484","tests/ui-msrv/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-msrv/transmute-mut-src-dst-generic.stderr":"ec064415b76e341316de3886f3222ab826c2621ea641eb62285b1814369f48c2","tests/ui-msrv/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-msrv/transmute-mut-src-dst-not-references.stderr":"fc2740d55afdb07bdde457ac259f48ef5b3e13503968299e51791576328b207d","tests/ui-msrv/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-msrv/transmute-mut-src-dst-unsized.stderr":"a47a39be560a9a80a31ebd6ee30178f2e375e9450c61a86effb3611f654e302c","tests/ui-msrv/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-msrv/transmute-mut-src-generic.stderr":"a7588c104a34936839fdef78029fdc3929f08f6befac2a94ef5fce5364cd89ca","tests/ui-msrv/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-msrv/transmute-mut-src-immutable.stderr":"6854b18881116cecf0c716eac01aac312bfe43a295a797c4ad01ac8b7ea7d81c","tests/ui-msrv/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-msrv/transmute-mut-src-not-a-reference.stderr":"538af460b18f588b6075307de50ba1307f98189d2f2aea74346a77ad8b64710c","tests/ui-msrv/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-msrv/transmute-mut-src-not-asbytes.stderr":"446ab2326cedeae89bd951561206dddcb546684629b12e46e3de1025caa7c894","tests/ui-msrv/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-msrv/transmute-mut-src-not-frombytes.stderr":"659915278b39092444f82347fbd62d4bd0c12cecb1d5976159b3fd90c8b995f2","tests/ui-msrv/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-msrv/transmute-mut-src-unsized.stderr":"7f9a60f0bafa5d59403e49f2a6b68a56fa2be6c2a62d785fe4cb51bc056159cc","tests/ui-msrv/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-msrv/transmute-ptr-to-usize.stderr":"e8713417a977f07158a58aec6690c3a79b49cf5edb9e66f6c1d218a1a55f47eb","tests/ui-msrv/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-msrv/transmute-ref-alignment-increase.stderr":"2c56277ab280ac4477ccd3ca4c48ac60e096a95579bfea58da81d9082d8ab499","tests/ui-msrv/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-msrv/transmute-ref-dst-generic.stderr":"8f47f9eabb44e8d5c561359237e79d42a998b615b526666e16db325b9cea8a09","tests/ui-msrv/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-msrv/transmute-ref-dst-mutable.stderr":"289e040b3e725546081dfd07640e499a5622915954f12c871708d3f46ff43d7a","tests/ui-msrv/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr":"b6c1f2aede85cce47f5ca379b9ae5a77c777e7c60de6590578c47432ebacae88","tests/ui-msrv/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr":"00b6c3472c0f84f4e32217c1c839c0eab1bf449abbc8bb8f60878ce62c360c8b","tests/ui-msrv/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-msrv/transmute-ref-dst-unsized.stderr":"73636b1d142730f1330753c3fa14c88a32a23bf1c0741503b99610a506a8f66b","tests/ui-msrv/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-msrv/transmute-ref-illegal-lifetime.stderr":"4f2a3e71cda94564f2343ca9ff23de3eca0d2ff465cedacab187151183813092","tests/ui-msrv/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-msrv/transmute-ref-size-decrease.stderr":"686597597e9f87e717b702bf6b8b6a52d14c5612ec267d48a01b442ab14648e1","tests/ui-msrv/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-msrv/transmute-ref-size-increase.stderr":"f1ad62609362a24b5cf47761e30e2cf0a35db82682e041faf251b2a1f822da7c","tests/ui-msrv/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-msrv/transmute-ref-src-dst-generic.stderr":"ca3c1493cbab64b5af7c3c4ea88ca16f6bb2478865b0dbe9d4a28d3b11d5fad1","tests/ui-msrv/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-msrv/transmute-ref-src-dst-not-references.stderr":"003bb1ccb5cf8322416e00e0fa5645f94d76aad875e60d281daae9625eb583a4","tests/ui-msrv/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-msrv/transmute-ref-src-dst-unsized.stderr":"558be2a5b90f3b3a304d5ae94ed3f7cd369e1e0ad03991ff57500913232ea8de","tests/ui-msrv/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-msrv/transmute-ref-src-generic.stderr":"2ba4f5f66b2a2eae90f2cb4b28bb92b066fcaf17412ca777e7d9823697d64736","tests/ui-msrv/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-msrv/transmute-ref-src-not-a-reference.stderr":"5a8d829089820ec79d9cd8d9ffac7dbde430914fdad691d46edcd96414d5cad0","tests/ui-msrv/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-msrv/transmute-ref-src-not-asbytes.stderr":"bbd65ef7225a7a39f8c53362a1f137a6b294227b0d2b658fa8082742cda4a8bf","tests/ui-msrv/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-msrv/transmute-ref-src-unsized.stderr":"68537a0c14f72addd12d9e2a75f1a965e730a7ee8da04303402ecd69fe6de95e","tests/ui-msrv/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-msrv/transmute-size-decrease.stderr":"978a9600a42a75fb33e46d10ac1485ef7c0a26054d15e52ec7e13023780d919e","tests/ui-msrv/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-msrv/transmute-size-increase.stderr":"168c9bb1045d125b069859d88132b7855a161e1353e1ff3d3f0bfcb70a831128","tests/ui-msrv/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-msrv/transmute-src-not-asbytes.stderr":"e5913ff39e19e7f38b7aebe19f1930810c898d34fb7e7815c1404eff715f0414","tests/ui-nightly/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-nightly/include_value_not_from_bytes.stderr":"f8b8bbf3be0b9f6f8a019aa268901c8a49fd78240c55cbb66d104443607673d6","tests/ui-nightly/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-nightly/include_value_wrong_size.stderr":"2b340b79ab4de286609aa5bf561c550ac3f30818df34bc659b54a58f4565501b","tests/ui-nightly/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-nightly/invalid-impls/invalid-impls.stderr":"f65bf5ae0342daf2f7b50c297fc395f1ffefd508d26be17cdf41e70a53e6901e","tests/ui-nightly/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-nightly/max-align.stderr":"e6a1e261b02aa0fded5a3f3e3cdda6afe067f0d1430d684e3d7bd24af2e8635a","tests/ui-nightly/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-nightly/transmute-dst-not-frombytes.stderr":"2a10d7770af3f90c2f63d836f7c96e20f7d7e5a02b3a6e0606630e5de688896f","tests/ui-nightly/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-nightly/transmute-mut-alignment-increase.stderr":"db521ff9c180434136b0e8421823435be8ed23c7ac85d9a83c479ad1b8153281","tests/ui-nightly/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-nightly/transmute-mut-const.stderr":"4ea82abf58a538b4524d7835b4ceaaa4c783997928c0d0297f386aba2079a5ef","tests/ui-nightly/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-nightly/transmute-mut-dst-generic.stderr":"d012039fa54f3d7cc8ee7275637964e7d83f8067545260676326b571bca46617","tests/ui-nightly/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr":"9d21ae45aff909bf6e6feca6c60fae8db1e4318935aede558bee1e243ede59f8","tests/ui-nightly/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr":"b943aed513868c0e03703a8e980a1b8d2aef5ec3c0d915fef89fd5c993d6f38e","tests/ui-nightly/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr":"911637625861f88bfc314d6903e2fae9e4eee663d085f7cdf8c96112a8e8a1b6","tests/ui-nightly/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-nightly/transmute-mut-dst-unsized.stderr":"185f7d73070819f2079f526d26ee8b67a782e267c6c18ff99bcba79faa8e5017","tests/ui-nightly/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-nightly/transmute-mut-illegal-lifetime.stderr":"b0379252732ca51314077fa20d3fb4bfcbee61f486229547c807ed0d7dede9c8","tests/ui-nightly/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-nightly/transmute-mut-size-decrease.stderr":"9294c2562503924704673967f93afbfd4b1d84abbf76318636105acdc3f37a63","tests/ui-nightly/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-nightly/transmute-mut-size-increase.stderr":"6858e39d6238843faa0ec4bf199f88d5013f1b50a811f5e882837f01eea00f93","tests/ui-nightly/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-nightly/transmute-mut-src-dst-generic.stderr":"f6a7bb45e58bf80a25a4e694e881f9c38f2a5d33817d9337d41a6d2c2aef93e8","tests/ui-nightly/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-nightly/transmute-mut-src-dst-not-references.stderr":"c871cb8a8e41cfe7bc04ecdd0196820370ba879c905bb200dd0310e63445b1ac","tests/ui-nightly/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-nightly/transmute-mut-src-dst-unsized.stderr":"1e525ac43daf9c0352139ba3414217590684e97902c65fd31a39b47a9ff97cab","tests/ui-nightly/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-nightly/transmute-mut-src-generic.stderr":"3c54bad3b3ab88b5c046bfb6ef79e0162ec7228447a1ba8321d9da754d536f20","tests/ui-nightly/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-nightly/transmute-mut-src-immutable.stderr":"8babe44bc71011b849c8496008449a7f9109e8e1121fd835a85029bb4c21afb5","tests/ui-nightly/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-nightly/transmute-mut-src-not-a-reference.stderr":"9fbd2270ad872bea0482068b37a0ee489ebf6acd3e0a68b0235da9c94b386407","tests/ui-nightly/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-nightly/transmute-mut-src-not-asbytes.stderr":"bcf055b807ef3da02755371c6473839be9fea88e848e92e0069a004fdea07fd1","tests/ui-nightly/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-nightly/transmute-mut-src-not-frombytes.stderr":"3a96311db2b3618019a0380244ae960f8642adb4b2c3a76b401c0df85ffd7e1f","tests/ui-nightly/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-nightly/transmute-mut-src-unsized.stderr":"cf973ad25465824647d50230c6965e5161f535b8336e37c9d2271749d89246da","tests/ui-nightly/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-nightly/transmute-ptr-to-usize.stderr":"f05ba5ad01e235eed456686a1ee5b7a668495c38054155965846d2bd613bd7d8","tests/ui-nightly/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-nightly/transmute-ref-alignment-increase.stderr":"aef92964ba843b890ce6c6b0924726dd89e1b9d6513f2148c269fe8fa203adac","tests/ui-nightly/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-nightly/transmute-ref-dst-generic.stderr":"06b9fcf8e0443f997c0ef5f8e2659afcb65f095b11162ea69488f89788b337a7","tests/ui-nightly/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-nightly/transmute-ref-dst-mutable.stderr":"96d38ce9a807ad7b60a846a8f5558c447da0d6cbe9225a077df4997712424d9a","tests/ui-nightly/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr":"8ed2540877865fcdfca6e150465996a8f2872eb122ed5d647825e9181ae64754","tests/ui-nightly/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr":"65d82eb523eeed4babc456616374b71cea0aaa21ab019281cd3ec3bb6ada05e4","tests/ui-nightly/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-nightly/transmute-ref-dst-unsized.stderr":"022fb4352cc105c4a358c5f7b903a55aac8e881ab623b6f5d527832e492c9a2f","tests/ui-nightly/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-nightly/transmute-ref-illegal-lifetime.stderr":"cb98c1b304334e58fc61be1c4b7782e68ab92d90a44c9627326d94d14a44cc38","tests/ui-nightly/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-nightly/transmute-ref-size-decrease.stderr":"14f6ea48e66c484e94f47c3af0983de06869a884cda19b2201548aadc2378758","tests/ui-nightly/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-nightly/transmute-ref-size-increase.stderr":"d5777c69b0ee36b6dcaf7699abb3ea03e1a8bac17bb5a1d4059ae28ff5f4357f","tests/ui-nightly/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-nightly/transmute-ref-src-dst-generic.stderr":"ebffb5c5318798ff84f1da69c3ba732b9af2ad3688ebd7b4b2770e2b201afccb","tests/ui-nightly/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-nightly/transmute-ref-src-dst-not-references.stderr":"0782e1b3e3137fe1137108d2d0aa685db107ac43af2192ff1e7ffef2e4a6453b","tests/ui-nightly/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-nightly/transmute-ref-src-dst-unsized.stderr":"d8717d6a9d644e7f9ffd3545235b2b9e7b828e4a66d9a0de030931f83096827e","tests/ui-nightly/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-nightly/transmute-ref-src-generic.stderr":"b53a09eca6226647cf53ee9bd0388e558def3bd1f8009b6ec74cc26e4db13d1c","tests/ui-nightly/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-nightly/transmute-ref-src-not-a-reference.stderr":"e4ef563eedda176adc05995d03ae328b8b8182bb682ffc323cf58211b467dff2","tests/ui-nightly/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-nightly/transmute-ref-src-not-asbytes.stderr":"00485cbb2eaaa8631e1d3ca4cbf77369490e34411c847c4122c15be85227ef98","tests/ui-nightly/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-nightly/transmute-ref-src-unsized.stderr":"657cd1fec23d8dab06f354dde93ac6989d049301edf3b2cd55b1e2e869095613","tests/ui-nightly/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-nightly/transmute-size-decrease.stderr":"4e014a129866804cf91cc3ff7a8ad1044ae1e3a6aad3b6ff8839605ab1b1df77","tests/ui-nightly/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-nightly/transmute-size-increase.stderr":"c307d7a2ae3d18e016be5d77e720bcf7023d03b10bb3ff3190e4d934eb9fc6a7","tests/ui-nightly/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-nightly/transmute-src-not-asbytes.stderr":"bb59ccb405a0737e51fff7d24aa15c65747eae0f6e0dcedb5557c185fe7e4667","tests/ui-stable/include_value_not_from_bytes.rs":"ea2a419e0c7ce12b4febe6139523184cba2b2c54c879177e0c58a5f78f0ec340","tests/ui-stable/include_value_not_from_bytes.stderr":"703b57e2287d1f2ec16511d4a12101d7e0bf357246b97fb2b9735f174380ef1d","tests/ui-stable/include_value_wrong_size.rs":"418e8c86ebf5a28ee50bd6ae00550f62a7a0ef3a7e7fda965b3d2337b64f2c66","tests/ui-stable/include_value_wrong_size.stderr":"b4fdeefd36bb2343f4e6cfae39c821fcfefd0671ea59205ffeea48318ce4fac7","tests/ui-stable/invalid-impls/invalid-impls.rs":"474d843ad40f3936adcd3ff592d815d8169813962ab9d99a68348b4b91aef10e","tests/ui-stable/invalid-impls/invalid-impls.stderr":"6458dc7e13558e98b459053a78b7bad24e2ad2a4444a8b26ed5efed10287972a","tests/ui-stable/max-align.rs":"ffcb6687c98e5629d01b17cbd0845ec195007cc39aa244b26a77d17688c8f13d","tests/ui-stable/max-align.stderr":"a8bd50e80cd0ae680a52ea71d06d259a43300dcfbf6b336a12cb371fe84e119b","tests/ui-stable/transmute-dst-not-frombytes.rs":"e00251eae67cdf8267a4963f212857a2a51de640a6f856c4b8df2a953caad25a","tests/ui-stable/transmute-dst-not-frombytes.stderr":"6e6b46fabef706ce760e498d34a728cb5a21791177722daa03de22daa41fee1c","tests/ui-stable/transmute-mut-alignment-increase.rs":"ba83c9cf01acf11352f7ee5b54cd73a451394fd78b8ddeb0637931c87adfd6ae","tests/ui-stable/transmute-mut-alignment-increase.stderr":"92f1cda35d0c41a93f93152ad5c77fcd2c9ae17a7f2b4d54a311d434aa586400","tests/ui-stable/transmute-mut-const.rs":"4227f4c0dda6d6128f41b209ecc2bf941c7659c8de84cc0e418862d279baa78f","tests/ui-stable/transmute-mut-const.stderr":"41ababb65f8bccee041dbb3edf43896a1473fc106c14ca02ccc553452c8658eb","tests/ui-stable/transmute-mut-dst-generic.rs":"aa015679b75dac0c37d5c43782b5e9522257f6ba34a10a89d0c1eba524a7af5c","tests/ui-stable/transmute-mut-dst-generic.stderr":"f2c60a1aae05ad780802b0290989c546abe35adcbcacf83a2264446a40ceb5dd","tests/ui-stable/transmute-mut-dst-not-a-reference.rs":"5d784ab588f081bfc304501f811a85ea2662f88fff8274ccbd53172ec255212c","tests/ui-stable/transmute-mut-dst-not-a-reference.stderr":"16a9cf4e0f90772d19c132f50dd0a85e60ecd929a6aa0820fbf568c7f6183d74","tests/ui-stable/transmute-mut-dst-not-asbytes.rs":"b1f986b3433980d7572a80511ca5a758c91e0c761d01c50bc73ed025d45698a6","tests/ui-stable/transmute-mut-dst-not-asbytes.stderr":"594b28711e85b0b246d9271e3575c62c32a01f36b8917c8e66b288031da753bc","tests/ui-stable/transmute-mut-dst-not-frombytes.rs":"a4353eeb67b4701908e694738c5c4ce965afe4432f14e00e740684352f5ddd30","tests/ui-stable/transmute-mut-dst-not-frombytes.stderr":"3fbf5b32de9e5b6818299196d0393d707cf018fa9773cd2446483e320a8caadd","tests/ui-stable/transmute-mut-dst-unsized.rs":"58c3423c07dd06ca98e61439f318ba5f3f7fc68ca9cb59371ebc482ad54709db","tests/ui-stable/transmute-mut-dst-unsized.stderr":"757959b30d40bbfe90218e3dadb0aa9f2933f970fcc45de999e5ece508926abf","tests/ui-stable/transmute-mut-illegal-lifetime.rs":"ec18bf7b3d9bd2674b43d0e04fc0545227473d43b07e2bbccc19c2068df33673","tests/ui-stable/transmute-mut-illegal-lifetime.stderr":"3a43e0be32ef3589fe3fa713d387bd3976bd8c75813f9641bbf7c539e10bed41","tests/ui-stable/transmute-mut-size-decrease.rs":"51aa423ec51a3c5579bbd7bac33adac8040629adc94eec3fb84825ef4f84f7bb","tests/ui-stable/transmute-mut-size-decrease.stderr":"b63870c4361917d4cd19fbaba433a9389b806135c9576ae8997c86f3b763fe3c","tests/ui-stable/transmute-mut-size-increase.rs":"ecc34f87b2ec668338672be6bac82b4056ebe35d98fd5d9a210f43f7e866b8e1","tests/ui-stable/transmute-mut-size-increase.stderr":"cb086ebcc60c4e17f8897c62c5b36b110b259c6e970825953798daf37144af47","tests/ui-stable/transmute-mut-src-dst-generic.rs":"613e00a353d1b359b57450bb408da585528f84b7eaf039a0c8d86bde1803395f","tests/ui-stable/transmute-mut-src-dst-generic.stderr":"ff7758361ba41d2bc3a49e9942e9f1f1b76d245f19a5391e45b9a066b8d0f6f4","tests/ui-stable/transmute-mut-src-dst-not-references.rs":"0b73d42fbcecba3483e24d4e9296d24d551de18822b45120e225356c5ccefad8","tests/ui-stable/transmute-mut-src-dst-not-references.stderr":"830581700736527e224bd923da3cd9c215e68556d2379c678174c08eff1501d6","tests/ui-stable/transmute-mut-src-dst-unsized.rs":"8ccf11a1990dbfd7ed7180c5e73e3a278f072f0a86eb2810f1b2c737ece76c57","tests/ui-stable/transmute-mut-src-dst-unsized.stderr":"daf408c8b529c0000fb4422b63ca0e98b29cdcc8c49c33ed305418cbaf430cca","tests/ui-stable/transmute-mut-src-generic.rs":"2cfe526643436df07247cc2583e1d097b247411185952132433127a159527669","tests/ui-stable/transmute-mut-src-generic.stderr":"de709f4435bf09ce98a6a9b19ac69560f85c43b665277ef60c9e62169e4a001f","tests/ui-stable/transmute-mut-src-immutable.rs":"606aba0c01726255c9be7e67a032ce854209c62dffec16d5dd2c8f484e19979a","tests/ui-stable/transmute-mut-src-immutable.stderr":"7c24d82d943695955b3ec1f0a53a349645fd3de1d549f3be989532e3774279bf","tests/ui-stable/transmute-mut-src-not-a-reference.rs":"e627a60c6f6d1b398bdcfc9307dbc57b268cc784b4967d1afaceed7eebd5db47","tests/ui-stable/transmute-mut-src-not-a-reference.stderr":"29b09aea59cfdb4b6535c5d33ec803539f28e53cce81938767ea0c22a1b1ce7d","tests/ui-stable/transmute-mut-src-not-asbytes.rs":"d0a6ddcfe31ac34ccc550090b80a67a010202bee12a39c230dd4374ef81a520c","tests/ui-stable/transmute-mut-src-not-asbytes.stderr":"91eba713b0f4e446f51910220686351187e55d43873ea49cc8a3c00312fe49cf","tests/ui-stable/transmute-mut-src-not-frombytes.rs":"5866e7d74baf3efb500338ba91a76f221e4a2479376e6921ec831fa284c9b3db","tests/ui-stable/transmute-mut-src-not-frombytes.stderr":"89351ba67ebc7fb3fe4e2da713d6b93deee1f2a3f81eaeb2ebceb5b469cae8cf","tests/ui-stable/transmute-mut-src-unsized.rs":"6676d8f29f0a32418f86d4423c464f4e0fdb8fe9ee8aa87f86c5fcdf8bd5e197","tests/ui-stable/transmute-mut-src-unsized.stderr":"28377ad3195fcffebb8c50980af4f7b5c5eb8c673b3ebf21e308a9c84f4cfa58","tests/ui-stable/transmute-ptr-to-usize.rs":"ea33dc39115509988d9abd6ac6536d88d82082417b21da9f9bc8cf8369c69618","tests/ui-stable/transmute-ptr-to-usize.stderr":"cba0e2d85a961b56d8fc2566bc555082b52f762ac36b9745e319bb5d1e726514","tests/ui-stable/transmute-ref-alignment-increase.rs":"a5028469f90ca572ec1c73131f9a8a0a1cbca47de0dcb9003ba98de378def783","tests/ui-stable/transmute-ref-alignment-increase.stderr":"514c5254a0e84051cb34bd700c08163a98195730b87e67acda8907d401311b6c","tests/ui-stable/transmute-ref-dst-generic.rs":"4a6b56491fd59646d1d1d8edbcc9d7de0dc69a9e6e4779f3cfd90e287f11557c","tests/ui-stable/transmute-ref-dst-generic.stderr":"0fa2e50dd2f259260511ae3534334420e4384d542daa8532c7d3a625652c2ada","tests/ui-stable/transmute-ref-dst-mutable.rs":"1c48caae9912f70dec5f5a99a0c880fe6a3022f11fd412438b8a1576803e5f73","tests/ui-stable/transmute-ref-dst-mutable.stderr":"fc83b5283cb5319fd7a2b79f94ed0a49f16bce5b222f7e1cc5ce5a879f3de650","tests/ui-stable/transmute-ref-dst-not-a-reference.rs":"c4b8a6c1970e30390d0a301e2dbe718b9eeef743299f7e91cd12c582ec203af7","tests/ui-stable/transmute-ref-dst-not-a-reference.stderr":"e8a126f4832344b8a69591fcc25e22bbbb29f2078b809a47f8afa40ac1087a1f","tests/ui-stable/transmute-ref-dst-not-frombytes.rs":"42aab9630fbab93f400713a1730d6dd6a89f821b0fa4dd5347aabe5e78b13aff","tests/ui-stable/transmute-ref-dst-not-frombytes.stderr":"dfb9cf0089d8040befa1413ad558a73b1b3d688c887c5712d5e0645a6c715b8c","tests/ui-stable/transmute-ref-dst-unsized.rs":"c374df8d00541fd34fff37e231e341501a427961f60d88ad3e3c375085cc060d","tests/ui-stable/transmute-ref-dst-unsized.stderr":"8a5410232b38b232921f6ae6d9b4ec6f5d3296aa21f8ebeda76faeeabb189941","tests/ui-stable/transmute-ref-illegal-lifetime.rs":"6812bbf7ec851a8591464f10864dbd1f225e65ed5793b6f6375cbe8a9db50b14","tests/ui-stable/transmute-ref-illegal-lifetime.stderr":"45ab741d710dc5a01a21ab64f99927e7da5593328b2037b9bc82a87bc0969136","tests/ui-stable/transmute-ref-size-decrease.rs":"939fb562e4678368e59fdafb3a597fd54a661fd09d9ecb23c6e626ff59b45384","tests/ui-stable/transmute-ref-size-decrease.stderr":"fec5ab0e3d885bbb8e7ab82d6d58b9b4ee35a1802502fbc494bafa086d4132cf","tests/ui-stable/transmute-ref-size-increase.rs":"f66ab294f7618abfac5c503570137759afceb0dd26c8802bb1786b8873fe5670","tests/ui-stable/transmute-ref-size-increase.stderr":"720e2150c9ed538cf00d7525124ab0cee6ac53e91582470e09c140db783fc2be","tests/ui-stable/transmute-ref-src-dst-generic.rs":"96a6f6580307e6a397af8ca688a8a65144dff5240372203bd9f02bad6a41fd1e","tests/ui-stable/transmute-ref-src-dst-generic.stderr":"25f15e5316df34cd4a438548090c287228f86062f7e2ef59ea17fb727b868a19","tests/ui-stable/transmute-ref-src-dst-not-references.rs":"7311602a0153b260d819e9608e8e66ef5904919a2349a95187919d8211e48e23","tests/ui-stable/transmute-ref-src-dst-not-references.stderr":"2bff9f290ec40458939a1633f850853b3486220cfd40bc24c4e52635b7455742","tests/ui-stable/transmute-ref-src-dst-unsized.rs":"f83e0225e824b7526d7732ef5d759b32358e5db50c3c6a318d2b5dcc2eb3c707","tests/ui-stable/transmute-ref-src-dst-unsized.stderr":"4331d74113a83df3e7077a50b7ee6ed6868834808b9ebb6982b1475f4e6afece","tests/ui-stable/transmute-ref-src-generic.rs":"ac1699aeca61c82aff5dac51d387a4ef7522faf2b2dfc56af398a2dc9d53745b","tests/ui-stable/transmute-ref-src-generic.stderr":"f3f8a7ee67ebec21169e1284c9eeaedcfa7b93c05f4e42c504cbd06508f34f9f","tests/ui-stable/transmute-ref-src-not-a-reference.rs":"a921f168fa6cb3c6a19894cecdb118bc3164275746672a916aa5194b92f2fb57","tests/ui-stable/transmute-ref-src-not-a-reference.stderr":"52efb101d85126138395fbed84c7cb911f86ea4457b991d91b2b6ec66521bcff","tests/ui-stable/transmute-ref-src-not-asbytes.rs":"09aabae9e4634a5432bf7225240954d7b0592994c97a927e0469e27854588232","tests/ui-stable/transmute-ref-src-not-asbytes.stderr":"7f2cc024e80cfc10e8ac21d016d940fce149014ad2664d3b9ef380b1bb69c14c","tests/ui-stable/transmute-ref-src-unsized.rs":"d7797488f0ab5db89944ac7db25625c63aef72e6e4ed481d00a083449050b813","tests/ui-stable/transmute-ref-src-unsized.stderr":"db7f3c025885a2f64559e63901cad5acb6baae5c20973fb6470edad6ba0cacc9","tests/ui-stable/transmute-size-decrease.rs":"c63dd10ddab58e282b033132d79fd21e80edb0c654f856679237977f62ced1ed","tests/ui-stable/transmute-size-decrease.stderr":"685acfb1b758f9854a5b36565f0b26cc1ef35322ee25387f05733187de1864d1","tests/ui-stable/transmute-size-increase.rs":"9413442e6e3c574bd7e36e8d4242000c1513624a4edc97567695a81b5851c491","tests/ui-stable/transmute-size-increase.stderr":"54cf03066a5d10ab7caa4741fe9d40df491a9a3fb81b6425a40bf04e21a6910e","tests/ui-stable/transmute-src-not-asbytes.rs":"8e2a76d99734c0502ba9daa8c7c2e34ca830ffd6024d3f7f29363d4263e89f74","tests/ui-stable/transmute-src-not-asbytes.stderr":"6a8f100e6da7f425c532370cd273b8af7f5f44450d0160ee73dbda8fe5f20a59"},"package":"1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"}
\ No newline at end of file
diff --git a/extra_versions/crates/zerocopy/Android.bp b/extra_versions/crates/zerocopy/Android.bp
new file mode 100644
index 0000000..49bb9f3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/Android.bp
@@ -0,0 +1,107 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+    default_applicable_licenses: ["external_rust_crates_zerocopy_license"],
+    default_team: "trendy_team_android_rust",
+}
+
+license {
+    name: "external_rust_crates_zerocopy_license",
+    visibility: [":__subpackages__"],
+    license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+    license_text: ["LICENSE"],
+}
+
+rust_library {
+    name: "libzerocopy",
+    host_supported: true,
+    crate_name: "zerocopy",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.7.35",
+    crate_root: "src/lib.rs",
+    edition: "2018",
+    features: [
+        "byteorder",
+        "derive",
+        "simd",
+        "zerocopy-derive",
+    ],
+    rustlibs: ["libbyteorder"],
+    proc_macros: ["libzerocopy_derive"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    product_available: true,
+    vendor_available: true,
+    min_sdk_version: "34",
+}
+
+rust_library_rlib {
+    name: "libzerocopy_nostd",
+    crate_name: "zerocopy",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.7.35",
+    crate_root: "src/lib.rs",
+    edition: "2018",
+    features: [
+        "alloc",
+        "byteorder",
+        "derive",
+        "simd",
+        "zerocopy-derive",
+    ],
+    rustlibs: ["libbyteorder_nostd"],
+    proc_macros: ["libzerocopy_derive"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    prefer_rlib: true,
+    no_stdlibs: true,
+    stdlibs: [
+        "liballoc.rust_sysroot",
+        "libcompiler_builtins.rust_sysroot",
+        "libcore.rust_sysroot",
+    ],
+    product_available: true,
+    vendor_available: true,
+    min_sdk_version: "34",
+}
+
+rust_library_rlib {
+    name: "libzerocopy_nostd_noalloc",
+    crate_name: "zerocopy",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.7.35",
+    crate_root: "src/lib.rs",
+    edition: "2018",
+    features: [
+        "byteorder",
+        "derive",
+        "simd",
+        "zerocopy-derive",
+    ],
+    rustlibs: ["libbyteorder_nostd"],
+    proc_macros: ["libzerocopy_derive"],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+    prefer_rlib: true,
+    no_stdlibs: true,
+    stdlibs: [
+        "libcompiler_builtins.rust_sysroot",
+        "libcore.rust_sysroot",
+    ],
+    product_available: true,
+    vendor_available: true,
+    min_sdk_version: "34",
+}
+
+dirgroup {
+    name: "trusty_dirgroup_external_rust_crates_zerocopy",
+    visibility: ["//trusty/vendor/google/aosp/scripts"],
+    dirs: ["."],
+}
diff --git a/extra_versions/crates/zerocopy/CONTRIBUTING.md b/extra_versions/crates/zerocopy/CONTRIBUTING.md
new file mode 100644
index 0000000..929e809
--- /dev/null
+++ b/extra_versions/crates/zerocopy/CONTRIBUTING.md
@@ -0,0 +1,215 @@
+<!-- Copyright 2022 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms. -->
+
+# How to Contribute
+
+We'd love to accept your patches and contributions to zerocopy. There are just a
+few small guidelines you need to follow.
+
+Once you've read the rest of this doc, check out our [good-first-issue
+label][good-first-issue] for some good issues you can use to get your toes wet!
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code Reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult [GitHub
+Help][about_pull_requests] for more information on using pull requests.
+
+## Code Guidelines
+
+### Philosophy
+
+This section is inspired by [Flutter's style guide][flutter_philosophy], which
+contains many general principles that you should apply to all your programming
+work. Read it. The below calls out specific aspects that we feel are
+particularly important.
+
+#### Dogfood Your Features
+
+In non-library code, it's often advised to only implement features you need.
+After all, it's hard to correctly design code without a concrete use case to
+guide its design. Since zerocopy is a library, this advice is not as applicable;
+we want our API surface to be featureful and complete even if not every feature
+or method has a known use case. However, the observation that unused code is
+hard to design still holds.
+
+Thus, when designing external-facing features, try to make use of them somehow.
+This could be by using them to implement other features, or it could be by
+writing prototype code which won't actually be checked in anywhere. If you're
+feeling ambitious, you could even add (and check in) a [Cargo
+example][cargo_example] that exercises the new feature.
+
+#### Go Down the Rabbit Hole
+
+You will occasionally encounter behavior that surprises you or seems wrong. It
+probably is! Invest the time to find the root cause - you will either learn
+something, or fix something, and both are worth your time. Do not work around
+behavior you don't understand.
+
+### Avoid Duplication
+
+Avoid duplicating code whenever possible. In cases where existing code is not
+exposed in a manner suitable to your needs, prefer to extract the necessary
+parts into a common dependency.
+
+### Comments
+
+When writing comments, take a moment to consider the future reader of your
+comment. Ensure that your comments are complete sentences with proper grammar
+and punctuation. Note that adding more comments or more verbose comments is not
+always better; for example, avoid comments that repeat the code they're anchored
+on.
+
+Documentation comments should be self-contained; in other words, do not assume
+that the reader is aware of documentation in adjacent files or on adjacent
+structures. Avoid documentation comments on types which describe _instances_ of
+the type; for example, `AddressSet is a set of client addresses.` is a comment
+that describes a field of type `AddressSet`, but the type may be used to hold
+any kind of `Address`, not just a client's.
+
+Phrase your comments to avoid references that might become stale; for example:
+do not mention a variable or type by name when possible (certain doc comments
+are necessary exceptions). Also avoid references to past or future versions of
+or past or future work surrounding the item being documented; explain things
+from first principles rather than making external references (including past
+revisions).
+
+When writing TODOs:
+
+1. Include an issue reference using the format `TODO(#123):`
+1. Phrase the text as an action that is to be taken; it should be possible for
+   another contributor to pick up the TODO without consulting any external
+   sources, including the referenced issue.
+
+### Tests
+
+Much of the code in zerocopy has the property that, if it is buggy, those bugs
+may not cause user code to fail. This makes it extra important to write thorough
+tests, but it also makes it harder to write those tests correctly. Here are some
+guidelines on how to test code in zerocopy:
+1. All code added to zerocopy must include tests that exercise it completely.
+1. Tests must be deterministic. Threaded or time-dependent code, random number
+   generators (RNGs), and communication with external processes are common
+   sources of nondeterminism. See [Write reproducible, deterministic
+   tests][determinism] for tips.
+1. Avoid [change detector tests][change_detector_tests]; tests that are
+   unnecessarily sensitive to changes, especially ones external to the code
+   under test, can hamper feature development and refactoring.
+1. Since we run tests in [Miri][miri], make sure that tests exist which exercise
+   any potential [undefined behavior][undefined_behavior] so that Miri can catch
+   it.
+1. If there's some user code that should be impossible to compile, add a
+   [trybuild test][trybuild] to ensure that it's properly rejected.
+
+### Source Control Best Practices
+
+Commits should be arranged for ease of reading; that is, incidental changes
+such as code movement or formatting changes should be committed separately from
+actual code changes.
+
+Commits should always be focused. For example, a commit could add a feature,
+fix a bug, or refactor code, but not a mixture.
+
+Commits should be thoughtfully sized; avoid overly large or complex commits
+which can be logically separated, but also avoid overly separated commits that
+require code reviews to load multiple commits into their mental working memory
+in order to properly understand how the various pieces fit together.
+
+#### Commit Messages
+
+Commit messages should be _concise_ but self-contained (avoid relying on issue
+references as explanations for changes) and written such that they are helpful
+to people reading in the future (include rationale and any necessary context).
+
+Avoid superfluous details or narrative.
+
+Commit messages should consist of a brief subject line and a separate
+explanatory paragraph in accordance with the following:
+
+1. [Separate subject from body with a blank line](https://chris.beams.io/posts/git-commit/#separate)
+1. [Limit the subject line to 50 characters](https://chris.beams.io/posts/git-commit/#limit-50)
+1. [Capitalize the subject line](https://chris.beams.io/posts/git-commit/#capitalize)
+1. [Do not end the subject line with a period](https://chris.beams.io/posts/git-commit/#end)
+1. [Use the imperative mood in the subject line](https://chris.beams.io/posts/git-commit/#imperative)
+1. [Wrap the body at 72 characters](https://chris.beams.io/posts/git-commit/#wrap-72)
+1. [Use the body to explain what and why vs. how](https://chris.beams.io/posts/git-commit/#why-not-how)
+
+If the code affects a particular subsystem, prefix the subject line with the
+name of that subsystem in square brackets, omitting any "zerocopy" prefix
+(that's implicit). For example, for a commit adding a feature to the
+zerocopy-derive crate:
+
+```text
+[derive] Support AsBytes on types with parameters
+```
+
+The body may be omitted if the subject is self-explanatory; e.g. when fixing a
+typo. The git book contains a [Commit Guidelines][commit_guidelines] section
+with much of the same advice, and the list above is part of a [blog
+post][beams_git_commit] by [Chris Beams][chris_beams].
+
+Commit messages should make use of issue integration. Including an issue
+reference like `#123` will cause the GitHub UI to link the text of that
+reference to the referenced issue, and will also make it so that the referenced
+issue back-links to the commit. Use "Closes", "Fixes", or "Resolves" on its own
+line to automatically close an issue when your commit is merged:
+
+```text
+Closes #123
+Fixes #123
+Resolves #123
+```
+
+When using issue integration, don't omit necessary context that may also be
+included in the relevant issue (see "Commit messages should be _concise_ but
+self-contained" above). Git history is more likely to be retained indefinitely
+than issue history (for example, if this repository is migrated away from GitHub
+at some point in the future).
+
+Commit messages should never contain references to any of:
+
+1. Relative moments in time
+1. Non-public URLs
+1. Individuals
+1. Hosted code reviews (such as on https://github.com/google/zerocopy/pulls)
+    + Refer to commits in this repository by their SHA-1 hash
+    + Refer to commits in other repositories by public web address (such as
+      https://github.com/google/zerocopy/commit/789b3deb)
+1. Other entities which may not make sense to arbitrary future readers
+
+## Community Guidelines
+
+This project follows [Google's Open Source Community
+Guidelines][google_open_source_guidelines].
+
+[about_pull_requests]: https://help.github.com/articles/about-pull-requests/
+[beams_git_commit]: https://chris.beams.io/posts/git-commit/
+[cargo_example]: http://xion.io/post/code/rust-examples.html
+[change_detector_tests]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html
+[chris_beams]: https://chris.beams.io/
+[commit_guidelines]: https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines
+[determinism]: https://fuchsia.dev/fuchsia-src/contribute/testing/best-practices#write_reproducible_deterministic_tests
+[flutter_philosophy]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#philosophy
+[good-first-issue]: https://github.com/google/zerocopy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
+[google_open_source_guidelines]: https://opensource.google/conduct/
+[magic_number]: https://en.wikipedia.org/wiki/Magic_number_(programming)
+[miri]: https://github.com/rust-lang/miri
+[trybuild]: https://crates.io/crates/trybuild
+[undefined_behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html
diff --git a/extra_versions/crates/zerocopy/Cargo.toml b/extra_versions/crates/zerocopy/Cargo.toml
new file mode 100644
index 0000000..3d3907c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/Cargo.toml
@@ -0,0 +1,101 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.60.0"
+name = "zerocopy"
+version = "0.7.35"
+authors = ["Joshua Liebow-Feeser <joshlf@google.com>"]
+exclude = [".*"]
+description = "Utilities for zero-copy parsing and serialization"
+readme = "README.md"
+keywords = [
+    "cast",
+    "convert",
+    "transmute",
+    "transmutation",
+    "type-punning",
+]
+categories = [
+    "embedded",
+    "encoding",
+    "no-std::no-alloc",
+    "parsing",
+    "rust-patterns",
+]
+license = "BSD-2-Clause OR Apache-2.0 OR MIT"
+repository = "https://github.com/google/zerocopy"
+
+[package.metadata.ci]
+pinned-nightly = "nightly-2024-06-19"
+pinned-stable = "1.79.0"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+    "--cfg",
+    "doc_cfg",
+    "--generate-link-to-definition",
+]
+
+[package.metadata.playground]
+features = ["__internal_use_only_features_that_work_on_stable"]
+
+[dependencies.byteorder]
+version = "1.3"
+optional = true
+default-features = false
+
+[dependencies.zerocopy-derive]
+version = "=0.7.35"
+optional = true
+
+[dev-dependencies.assert_matches]
+version = "1.5"
+
+[dev-dependencies.elain]
+version = "0.3.0"
+
+[dev-dependencies.itertools]
+version = "0.11"
+
+[dev-dependencies.rand]
+version = "0.8.5"
+features = ["small_rng"]
+
+[dev-dependencies.rustversion]
+version = "1.0"
+
+[dev-dependencies.static_assertions]
+version = "1.1"
+
+[dev-dependencies.trybuild]
+version = "=1.0.85"
+features = ["diff"]
+
+[dev-dependencies.zerocopy-derive]
+version = "=0.7.35"
+
+[features]
+__internal_use_only_features_that_work_on_stable = [
+    "alloc",
+    "derive",
+    "simd",
+]
+alloc = []
+default = ["byteorder"]
+derive = ["zerocopy-derive"]
+simd = []
+simd-nightly = ["simd"]
+
+[target."cfg(any())".dependencies.zerocopy-derive]
+version = "=0.7.35"
diff --git a/extra_versions/crates/zerocopy/INTERNAL.md b/extra_versions/crates/zerocopy/INTERNAL.md
new file mode 100644
index 0000000..4e7f440
--- /dev/null
+++ b/extra_versions/crates/zerocopy/INTERNAL.md
@@ -0,0 +1,44 @@
+<!-- Copyright 2022 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms. -->
+
+# Internal details
+
+This file documents various internal details of zerocopy and its infrastructure
+that consumers don't need to be concerned about. It focuses on details that
+affect multiple files, and allows each affected code location to reference this
+document rather than requiring us to repeat the same explanation in multiple
+locations.
+
+## CI and toolchain versions
+
+In CI (`.github/workflows/ci.yml`), we pin to specific versions or dates of the
+stable and nightly toolchains. The reason is twofold: First, our UI tests (see
+`tests/trybuild.rs` and `zerocopy-derive/tests/trybuild.rs`) depend on the
+format of rustc's error messages, and that format can change between toolchain
+versions (we also maintain multiple copies of our UI tests - one for each
+toolchain version pinned in CI - for this reason). Second, not all nightlies
+have a working Miri, so we need to pin to one that does (see
+https://rust-lang.github.io/rustup-components-history/).
+
+Updating the versions pinned in CI may cause the UI tests to break. In order to
+fix UI tests after a version update, run:
+
+```
+$ TRYBUILD=overwrite ./cargo.sh +all test
+```
+
+## Crate versions
+
+We ensure that the crate versions of zerocopy and zerocopy-derive are always the
+same in-tree, and that zerocopy depends upon zerocopy-derive using an exact
+version match to the current version in-tree. This has the result that, even
+when published on crates.io, both crates effectively constitute a single atomic
+version. So long as the code in zerocopy is compatible with the code in
+zerocopy-derive in the same Git commit, then publishing them both is fine. This
+frees us from the normal task of reasoning about compatibility with a range of
+semver-compatible versions of different crates.
diff --git a/extra_versions/crates/zerocopy/LICENSE b/extra_versions/crates/zerocopy/LICENSE
new file mode 100644
index 0000000..7ed244f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2019 The Fuchsia Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy/LICENSE-APACHE b/extra_versions/crates/zerocopy/LICENSE-APACHE
new file mode 100644
index 0000000..2dc22c1
--- /dev/null
+++ b/extra_versions/crates/zerocopy/LICENSE-APACHE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2023 The Fuchsia Authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/extra_versions/crates/zerocopy/LICENSE-BSD b/extra_versions/crates/zerocopy/LICENSE-BSD
new file mode 100644
index 0000000..7ed244f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/LICENSE-BSD
@@ -0,0 +1,24 @@
+Copyright 2019 The Fuchsia Authors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy/LICENSE-MIT b/extra_versions/crates/zerocopy/LICENSE-MIT
new file mode 100644
index 0000000..26e1521
--- /dev/null
+++ b/extra_versions/crates/zerocopy/LICENSE-MIT
@@ -0,0 +1,26 @@
+Copyright 2023 The Fuchsia Authors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
diff --git a/extra_versions/crates/zerocopy/METADATA b/extra_versions/crates/zerocopy/METADATA
new file mode 100644
index 0000000..ec1ede5
--- /dev/null
+++ b/extra_versions/crates/zerocopy/METADATA
@@ -0,0 +1,24 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/rust/crates/zerocopy
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
+
+name: "zerocopy"
+description: "Utilities for zero-copy parsing and serialization"
+third_party {
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2024
+    month: 9
+    day: 5
+  }
+  identifier {
+    type: "crates.io"
+    value: "https://crates.io/crates/zerocopy"
+    version: ""
+  }
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/zerocopy/zerocopy-0.7.35.crate"
+    version: "0.7.35"
+  }
+}
diff --git a/extra_versions/crates/zerocopy/MODULE_LICENSE_BSD_LIKE b/extra_versions/crates/zerocopy/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/extra_versions/crates/zerocopy/MODULE_LICENSE_BSD_LIKE
diff --git a/extra_versions/crates/zerocopy/POLICIES.md b/extra_versions/crates/zerocopy/POLICIES.md
new file mode 100644
index 0000000..7f6e148
--- /dev/null
+++ b/extra_versions/crates/zerocopy/POLICIES.md
@@ -0,0 +1,114 @@
+<!-- Copyright 2023 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms. -->
+
+# Zerocopy's Policies
+
+## Soundness
+
+Zerocopy is expressly designed for use in security-critical contexts. It is used
+in hardware security firmware, cryptographic implementations, hypervisors, and
+more. We understand that software in these contexts has a very high bar for
+correctness, and we take our responsibility to meet that bar very seriously.
+
+This section describes policies which are designed to ensure the correctness and
+soundness of our code and prevent regressions.
+
+### Forwards-compatibility
+
+Rust does not currently have a formal memory model. As such, while Rust provides
+guarantees about the semantics of some operations, the semantics of many
+operations is up in the air and subject to change.
+
+Zerocopy strives to ensure that our code - and code emitted by our custom
+derives - is sound under any version of Rust as early as our MSRV, and will
+continue to be sound under any future version of Rust. The policies in this
+section are designed to help ensure that we live up to this goal.
+
+### Safety comments
+
+Each non-test `unsafe` block must be annotated with a "safety comment" which
+provides a rationale for its soundness. In order to ensure that our soundness is
+forwards-compatible, safety comments must satisfy the following criteria:
+- Safety comments must constitute a (possibly informal) proof that all of Rust's
+  soundness rules are upheld.
+- Safety comments must only rely for their correctness on statements which
+  appear in the stable versions of the [Rust Reference] or standard library
+  documentation (ie, the docs for [core], [alloc], and [std]); arguments which
+  rely on text from the beta or nightly versions of these documents are not
+  considered complete.
+- All statements from the Reference or standard library documentation which are
+  relied upon for soundness must be quoted in the safety comment. This ensures
+  that there is no ambiguity as to what aspect of the text is being cited. This
+  is especially important in cases where the text of these documents changes in
+  the future. Such changes are of course required to be backwards-compatible,
+  but may change the manner in which a particular guarantee is explained.
+
+We use the [`clippy::undocumented_unsafe_blocks`] lint to ensure that `unsafe`
+blocks cannot be added without a safety comment. Note that there are a few
+outstanding uncommented `unsafe` blocks which are tracked in [#429]. Our goal is
+to reach 100% safety comment coverage and not regress once we've reached it.
+
+[Rust Reference]: https://doc.rust-lang.org/reference/
+[core]: https://doc.rust-lang.org/stable/core/
+[alloc]: https://doc.rust-lang.org/stable/alloc/
+[std]: https://doc.rust-lang.org/stable/std/
+[`clippy::undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#/undocumented_unsafe_blocks
+[#429]: https://github.com/google/zerocopy/issues/429
+
+#### Exceptions to our safety comment policy
+
+In rare circumstances, the soundness of an `unsafe` block may depend upon
+semantics which are widely agreed upon but not formally guaranteed. In order to
+avoid slowing down zerocopy's development to an unreasonable degree, a safety
+comment may violate our safety comment policy so long as all of the following
+hold:
+- The safety comment's correctness may rely on semantics which are not
+  guaranteed in official Rust documentation *so long as* a member of the Rust
+  team has articulated in an official communication (e.g. a comment on a Rust
+  GitHub repo) that Rust intends to guarantee particular semantics.
+- There exists an active effort to formalize the guarantee in Rust's official
+  documentation.
+
+### Target architecture support
+
+Zerocopy bases its soundness on guarantees made about the semantics of Rust
+which appear in the Rust Reference or standard library documentation; zerocopy
+is sound so long as these guarantees hold. There are known cases in which these
+guarantees do not hold on certain target architectures (see
+[rust-lang/unsafe-code-guidelines#461]); on such target architectures, zerocopy
+may be unsound. We consider it outside of zerocopy's scope to reason about these
+cases. Zerocopy makes no effort maintain soundness in cases where Rust's
+documented guarantees do not hold.
+
+[rust-lang/unsafe-code-guidelines#461]: https://github.com/rust-lang/unsafe-code-guidelines/issues/461
+
+## MSRV
+
+<!-- Our policy used to be simply that MSRV was a breaking change in all
+circumstances. This implicitly relied on syn having the same MSRV policy, which
+it does not. See #1085 and #1088. -->
+
+Without the `derive` feature enabled, zerocopy's minimum supported Rust version
+(MSRV) is encoded the `package.rust-version` field in its `Cargo.toml` file. For
+zerocopy, we consider an increase in MSRV to be a semver-breaking change, and
+will only increase our MSRV during semver-breaking version changes (e.g., 0.1 ->
+0.2, 1.0 -> 2.0, etc).
+
+For zerocopy with the `derive` feature enabled, and for the zerocopy-derive
+crate, we inherit the MSRV of our sole external dependency, syn. As of this
+writing (2024-07-02), syn does *not* consider MSRV increases to be
+semver-breaking changes. Thus, using the `derive` feature may result in the
+effective MSRV increasing within a semver version train.
+
+## Yanking
+
+Whenever a bug or regression is identified, we will yank any affected versions
+which are part of the current version train. For example, if the most recent
+version is 0.10.20 and a bug is uncovered, we will release a fix in 0.10.21 and
+yank all 0.10.X versions which are affected. We *may* also yank versions in previous
+version trains on a case-by-case basis, but we don't guarantee it.
diff --git a/extra_versions/crates/zerocopy/README.md b/extra_versions/crates/zerocopy/README.md
new file mode 100644
index 0000000..ec09c45
--- /dev/null
+++ b/extra_versions/crates/zerocopy/README.md
@@ -0,0 +1,154 @@
+<!-- Copyright 2022 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms.
+
+WARNING: DO NOT EDIT THIS FILE. It is generated automatically. Edits should be
+made in the doc comment on `src/lib.rs` or in `generate-readme.sh`.
+-->
+
+# zerocopy
+
+*<span style="font-size: 100%; color:grey;">Want to help improve zerocopy?
+Fill out our [user survey][user-survey]!</span>*
+
+***<span style="font-size: 140%">Fast, safe, <span
+style="color:red;">compile error</span>. Pick two.</span>***
+
+Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe`
+so you don't have to.
+
+## Overview
+
+Zerocopy provides four core marker traits, each of which can be derived
+(e.g., `#[derive(FromZeroes)]`):
+- `FromZeroes` indicates that a sequence of zero bytes represents a valid
+  instance of a type
+- `FromBytes` indicates that a type may safely be converted from an
+  arbitrary byte sequence
+- `AsBytes` indicates that a type may safely be converted *to* a byte
+  sequence
+- `Unaligned` indicates that a type's alignment requirement is 1
+
+Types which implement a subset of these traits can then be converted to/from
+byte sequences with little to no runtime overhead.
+
+Zerocopy also provides byte-order aware integer types that support these
+conversions; see the `byteorder` module. These types are especially useful
+for network parsing.
+
+[user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options
+
+## Cargo Features
+
+- **`alloc`**
+  By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled,
+  the `alloc` crate is added as a dependency, and some allocation-related
+  functionality is added.
+
+- **`byteorder`** (enabled by default)
+  Adds the `byteorder` module and a dependency on the `byteorder` crate.
+  The `byteorder` module provides byte order-aware equivalents of the
+  multi-byte primitive numerical types. Unlike their primitive equivalents,
+  the types in this module have no alignment requirement and support byte
+  order conversions. This can be useful in handling file formats, network
+  packet layouts, etc which don't provide alignment guarantees and which may
+  use a byte order different from that of the execution platform.
+
+- **`derive`**
+  Provides derives for the core marker traits via the `zerocopy-derive`
+  crate. These derives are re-exported from `zerocopy`, so it is not
+  necessary to depend on `zerocopy-derive` directly.
+
+  However, you may experience better compile times if you instead directly
+  depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`,
+  since doing so will allow Rust to compile these crates in parallel. To do
+  so, do *not* enable the `derive` feature, and list both dependencies in
+  your `Cargo.toml` with the same leading non-zero version number; e.g:
+
+  ```toml
+  [dependencies]
+  zerocopy = "0.X"
+  zerocopy-derive = "0.X"
+  ```
+
+- **`simd`**
+  When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and
+  `AsBytes` impls are emitted for all stable SIMD types which exist on the
+  target platform. Note that the layout of SIMD types is not yet stabilized,
+  so these impls may be removed in the future if layout changes make them
+  invalid. For more information, see the Unsafe Code Guidelines Reference
+  page on the [layout of packed SIMD vectors][simd-layout].
+
+- **`simd-nightly`**
+  Enables the `simd` feature and adds support for SIMD types which are only
+  available on nightly. Since these types are unstable, support for any type
+  may be removed at any point in the future.
+
+[simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
+
+## Security Ethos
+
+Zerocopy is expressly designed for use in security-critical contexts. We
+strive to ensure that that zerocopy code is sound under Rust's current
+memory model, and *any future memory model*. We ensure this by:
+- **...not 'guessing' about Rust's semantics.**
+  We annotate `unsafe` code with a precise rationale for its soundness that
+  cites a relevant section of Rust's official documentation. When Rust's
+  documented semantics are unclear, we work with the Rust Operational
+  Semantics Team to clarify Rust's documentation.
+- **...rigorously testing our implementation.**
+  We run tests using [Miri], ensuring that zerocopy is sound across a wide
+  array of supported target platforms of varying endianness and pointer
+  width, and across both current and experimental memory models of Rust.
+- **...formally proving the correctness of our implementation.**
+  We apply formal verification tools like [Kani][kani] to prove zerocopy's
+  correctness.
+
+For more information, see our full [soundness policy].
+
+[Miri]: https://github.com/rust-lang/miri
+[Kani]: https://github.com/model-checking/kani
+[soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness
+
+## Relationship to Project Safe Transmute
+
+[Project Safe Transmute] is an official initiative of the Rust Project to
+develop language-level support for safer transmutation. The Project consults
+with crates like zerocopy to identify aspects of safer transmutation that
+would benefit from compiler support, and has developed an [experimental,
+compiler-supported analysis][mcp-transmutability] which determines whether,
+for a given type, any value of that type may be soundly transmuted into
+another type. Once this functionality is sufficiently mature, zerocopy
+intends to replace its internal transmutability analysis (implemented by our
+custom derives) with the compiler-supported one. This change will likely be
+an implementation detail that is invisible to zerocopy's users.
+
+Project Safe Transmute will not replace the need for most of zerocopy's
+higher-level abstractions. The experimental compiler analysis is a tool for
+checking the soundness of `unsafe` code, not a tool to avoid writing
+`unsafe` code altogether. For the foreseeable future, crates like zerocopy
+will still be required in order to provide higher-level abstractions on top
+of the building block provided by Project Safe Transmute.
+
+[Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html
+[mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411
+
+## MSRV
+
+See our [MSRV policy].
+
+[MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv
+
+## Changelog
+
+Zerocopy uses [GitHub Releases].
+
+[GitHub Releases]: https://github.com/google/zerocopy/releases
+
+## Disclaimer
+
+Disclaimer: Zerocopy is not an officially supported Google product.
diff --git a/extra_versions/crates/zerocopy/TEST_MAPPING b/extra_versions/crates/zerocopy/TEST_MAPPING
new file mode 100644
index 0000000..71b8cda
--- /dev/null
+++ b/extra_versions/crates/zerocopy/TEST_MAPPING
@@ -0,0 +1,8 @@
+// Generated by update_crate_tests.py for tests that depend on this crate.
+{
+  "imports": [
+    {
+      "path": "external/rust/crates/virtio-drivers"
+    }
+  ]
+}
diff --git a/extra_versions/crates/zerocopy/cargo.sh b/extra_versions/crates/zerocopy/cargo.sh
new file mode 100755
index 0000000..f72e898
--- /dev/null
+++ b/extra_versions/crates/zerocopy/cargo.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+#
+# Copyright 2023 The Fuchsia Authors
+#
+# Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+# <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+# license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+# This file may not be copied, modified, or distributed except according to
+# those terms.
+
+# This script is a thin wrapper around Cargo that provides human-friendly
+# toolchain names which are automatically translated to the toolchain versions
+# we have pinned in CI.
+#
+#   cargo.sh --version <toolchain-name> # looks up the version for the named toolchain
+#   cargo.sh +<toolchain-name> [...]    # runs cargo commands with the named toolchain
+#   cargo.sh +all [...]                 # runs cargo commands with each toolchain
+#
+# The meta-toolchain "all" instructs this script to run the provided command
+# once for each toolchain (msrv, stable, nightly).
+#
+# A common task that is especially annoying to perform by hand is to update
+# trybuild's stderr files. Using this script:
+#
+#   TRYBUILD=overwrite ./cargo.sh +all test --workspace
+
+set -eo pipefail
+
+function print-usage-and-exit {
+  echo "Usage:"                          >&2
+  echo "  $0 --version <toolchain-name>" >&2
+  echo "  $0 +<toolchain-name> [...]"    >&2
+  echo "  $0 +all [...]"    >&2
+  exit 1
+}
+
+[[ $# -gt 0 ]] || print-usage-and-exit
+
+function pkg-meta {
+  # NOTE(#547): We set `CARGO_TARGET_DIR` here because `cargo metadata`
+  # sometimes causes the `cargo-metadata` crate to be rebuilt from source using
+  # the default toolchain. This has the effect of clobbering any existing build
+  # artifacts from whatever toolchain the user has specified (e.g., `+nightly`),
+  # causing the subsequent `cargo` invocation to rebuild unnecessarily. By
+  # specifying a separate build directory here, we ensure that this never
+  # clobbers the build artifacts used by the later `cargo` invocation.
+  CARGO_TARGET_DIR=target/cargo-sh cargo metadata --format-version 1 | jq -r ".packages[] | select(.name == \"zerocopy\").$1"
+}
+
+function lookup-version {
+  VERSION="$1"
+  case "$VERSION" in
+    msrv)
+      pkg-meta rust_version
+      ;;
+    stable)
+      pkg-meta 'metadata.ci."pinned-stable"'
+      ;;
+    nightly)
+      pkg-meta 'metadata.ci."pinned-nightly"'
+      ;;
+    *)
+      echo "Unrecognized toolchain name: '$VERSION' (options are 'msrv', 'stable', 'nightly')" >&2
+      return 1
+      ;;
+  esac
+}
+
+function get-rustflags {
+  [ "$1" == nightly ] && echo "--cfg __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS"
+}
+
+function prompt {
+  PROMPT="$1"
+  YES="$2"
+  while true; do
+    read -p "$PROMPT " yn
+    case "$yn" in
+      [Yy]) $YES; return $?; ;;
+      [Nn])       return 1;  ;;
+      *)          break;     ;;
+    esac
+  done
+}
+
+case "$1" in
+  # cargo.sh --version <toolchain-name>
+  --version)
+    [[ $# -eq 2 ]] || print-usage-and-exit
+    lookup-version "$2"
+    ;;
+  # cargo.sh +all [...]
+  +all)
+    echo "[cargo.sh] warning: running the same command for each toolchain (msrv, stable, nightly)" >&2
+    for toolchain in msrv stable nightly; do
+      echo "[cargo.sh] running with toolchain: $toolchain" >&2
+      $0 "+$toolchain" ${@:2}
+    done
+    exit 0
+    ;;
+  # cargo.sh +<toolchain-name> [...]
+  +*)
+    TOOLCHAIN="$(lookup-version ${1:1})"
+
+    cargo "+$TOOLCHAIN" version &>/dev/null && \
+    rustup "+$TOOLCHAIN" component list | grep '^rust-src (installed)$' >/dev/null || {
+      echo "[cargo.sh] missing either toolchain '$TOOLCHAIN' or component 'rust-src'" >&2
+      # If we're running in a GitHub action, then it's better to bail than to
+      # hang waiting for input we're never going to get.
+      [ -z ${GITHUB_RUN_ID+x} ] || exit 1
+      prompt "[cargo.sh] would you like to install toolchain '$TOOLCHAIN' and component 'rust-src' via 'rustup'?" \
+        "rustup toolchain install $TOOLCHAIN -c rust-src"
+    } || exit 1
+
+    RUSTFLAGS="$(get-rustflags ${1:1}) $RUSTFLAGS" cargo "+$TOOLCHAIN" ${@:2}
+    ;;
+  *)
+    print-usage-and-exit
+    ;;
+esac
diff --git a/extra_versions/crates/zerocopy/cargo_embargo.json b/extra_versions/crates/zerocopy/cargo_embargo.json
new file mode 100644
index 0000000..315b9c6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/cargo_embargo.json
@@ -0,0 +1,66 @@
+{
+  "run_cargo": false,
+  "variants": [
+    {
+      "features": [
+        "derive",
+        "byteorder",
+        "simd"
+      ]
+    },
+    {
+      "features": [
+        "alloc",
+        "derive",
+        "byteorder",
+        "simd"
+      ],
+      "module_name_overrides": {
+        "libbyteorder": "libbyteorder_nostd",
+        "libzerocopy": "libzerocopy_nostd"
+      },
+      "package": {
+        "zerocopy": {
+          "alloc": true,
+          "force_rlib": true,
+          "host_supported": false,
+          "no_std": true
+        }
+      }
+    },
+    {
+      "features": [
+        "derive",
+        "byteorder",
+        "simd"
+      ],
+      "module_name_overrides": {
+        "libbyteorder": "libbyteorder_nostd",
+        "libzerocopy": "libzerocopy_nostd_noalloc"
+      },
+      "package": {
+        "zerocopy": {
+          "force_rlib": true,
+          "host_supported": false,
+          "no_std": true
+        }
+      }
+    },
+    {
+      "features": [
+        "alloc",
+        "derive",
+        "byteorder"
+      ],
+      "package": {
+        "zerocopy": {
+          "alloc": true,
+          "no_std": true
+        }
+      },
+      "generate_androidbp": false,
+      "generate_rulesmk": true
+    }
+  ],
+  "min_sdk_version": "34"
+}
diff --git a/extra_versions/crates/zerocopy/clippy.toml b/extra_versions/crates/zerocopy/clippy.toml
new file mode 100644
index 0000000..9c11406
--- /dev/null
+++ b/extra_versions/crates/zerocopy/clippy.toml
@@ -0,0 +1,10 @@
+# Copyright 2023 The Fuchsia Authors
+#
+# Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+# <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+# license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+# This file may not be copied, modified, or distributed except according to
+# those terms.
+
+accept-comment-above-statement = true
+accept-comment-above-attributes = true
diff --git a/extra_versions/crates/zerocopy/generate-readme.sh b/extra_versions/crates/zerocopy/generate-readme.sh
new file mode 100755
index 0000000..be0dc92
--- /dev/null
+++ b/extra_versions/crates/zerocopy/generate-readme.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copyright 2022 The Fuchsia Authors
+#
+# Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+# <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+# license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+# This file may not be copied, modified, or distributed except according to
+# those terms.
+
+set -eo pipefail
+
+COPYRIGHT_HEADER=$(mktemp)
+BODY=$(mktemp)
+DISCLAIMER_FOOTER=$(mktemp)
+
+cat > $COPYRIGHT_HEADER <<'EOF'
+<!-- Copyright 2022 The Fuchsia Authors
+
+Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+<LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+This file may not be copied, modified, or distributed except according to
+those terms.
+
+WARNING: DO NOT EDIT THIS FILE. It is generated automatically. Edits should be
+made in the doc comment on `src/lib.rs` or in `generate-readme.sh`.
+-->
+
+EOF
+
+# This uses the `cargo readme` tool, which you can install via `cargo install
+# cargo-readme --version 3.2.0`.
+#
+# The `sed` command is used to strip code links like:
+#
+#   /// Here is a link to [`Vec`].
+#
+# These links don't work in a Markdown file, and so we remove the `[` and `]`
+# characters to convert them to non-link code snippets.
+cargo readme --no-license | sed 's/\[\(`[^`]*`\)]/\1/g' > $BODY
+
+cat > $DISCLAIMER_FOOTER <<'EOF'
+
+## Disclaimer
+
+Disclaimer: Zerocopy is not an officially supported Google product.
+EOF
+
+cat $COPYRIGHT_HEADER $BODY $DISCLAIMER_FOOTER
diff --git a/extra_versions/crates/zerocopy/patches/LICENSE.patch b/extra_versions/crates/zerocopy/patches/LICENSE.patch
new file mode 100644
index 0000000..150d4e0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/patches/LICENSE.patch
@@ -0,0 +1,30 @@
+diff --git b/LICENSE a/LICENSE
+new file mode 100644
+index 0000000..7ed244f
+--- /dev/null
++++ a/LICENSE
+@@ -0,0 +1,24 @@
++Copyright 2019 The Fuchsia Authors.
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are
++met:
++
++   * Redistributions of source code must retain the above copyright
++notice, this list of conditions and the following disclaimer.
++   * Redistributions in binary form must reproduce the above
++copyright notice, this list of conditions and the following disclaimer
++in the documentation and/or other materials provided with the
++distribution.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extra_versions/crates/zerocopy/rules.mk b/extra_versions/crates/zerocopy/rules.mk
new file mode 100644
index 0000000..71e086b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/rules.mk
@@ -0,0 +1,26 @@
+# This file is generated by cargo_embargo.
+# Do not modify this file after the LOCAL_DIR line
+# because the changes will be overridden on upgrade.
+# Content before the first line starting with LOCAL_DIR is preserved.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+MODULE := $(LOCAL_DIR)
+MODULE_CRATE_NAME := zerocopy
+MODULE_RUST_CRATE_TYPES := rlib
+MODULE_SRCS := $(LOCAL_DIR)/src/lib.rs
+MODULE_ADD_IMPLICIT_DEPS := false
+MODULE_RUST_EDITION := 2018
+MODULE_RUSTFLAGS += \
+	--cfg 'feature="alloc"' \
+	--cfg 'feature="byteorder"' \
+	--cfg 'feature="derive"' \
+	--cfg 'feature="zerocopy-derive"'
+
+MODULE_LIBRARY_DEPS := \
+	$(call FIND_CRATE,byteorder) \
+	$(call FIND_CRATE,zerocopy-derive) \
+	trusty/user/base/lib/liballoc-rust \
+	trusty/user/base/lib/libcompiler_builtins-rust \
+	trusty/user/base/lib/libcore-rust
+
+include make/library.mk
diff --git a/extra_versions/crates/zerocopy/rustfmt.toml b/extra_versions/crates/zerocopy/rustfmt.toml
new file mode 100644
index 0000000..c967afe
--- /dev/null
+++ b/extra_versions/crates/zerocopy/rustfmt.toml
@@ -0,0 +1,19 @@
+# Copyright 2022 The Fuchsia Authors
+#
+# Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+# <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+# license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+# This file may not be copied, modified, or distributed except according to
+# those terms.
+
+edition = "2021"
+
+# The "Default" setting has a heuristic which splits lines too aggresively.
+# We are willing to revisit this setting in future versions of rustfmt.
+# Bugs:
+#   * https://github.com/rust-lang/rustfmt/issues/3119
+#   * https://github.com/rust-lang/rustfmt/issues/3120
+use_small_heuristics = "Max"
+
+# Prevent carriage returns
+newline_style = "Unix"
diff --git a/extra_versions/crates/zerocopy/src/byteorder.rs b/extra_versions/crates/zerocopy/src/byteorder.rs
new file mode 100644
index 0000000..376c981
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/byteorder.rs
@@ -0,0 +1,1071 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Byte order-aware numeric primitives.
+//!
+//! This module contains equivalents of the native multi-byte integer types with
+//! no alignment requirement and supporting byte order conversions.
+//!
+//! For each native multi-byte integer type - `u16`, `i16`, `u32`, etc - and
+//! floating point type - `f32` and `f64` - an equivalent type is defined by
+//! this module - [`U16`], [`I16`], [`U32`], [`F64`], etc. Unlike their native
+//! counterparts, these types have alignment 1, and take a type parameter
+//! specifying the byte order in which the bytes are stored in memory. Each type
+//! implements the [`FromBytes`], [`AsBytes`], and [`Unaligned`] traits.
+//!
+//! These two properties, taken together, make these types useful for defining
+//! data structures whose memory layout matches a wire format such as that of a
+//! network protocol or a file format. Such formats often have multi-byte values
+//! at offsets that do not respect the alignment requirements of the equivalent
+//! native types, and stored in a byte order not necessarily the same as that of
+//! the target platform.
+//!
+//! Type aliases are provided for common byte orders in the [`big_endian`],
+//! [`little_endian`], [`network_endian`], and [`native_endian`] submodules.
+//!
+//! # Example
+//!
+//! One use of these types is for representing network packet formats, such as
+//! UDP:
+//!
+//! ```rust,edition2021
+//! # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them
+//! use zerocopy::{AsBytes, ByteSlice, FromBytes, FromZeroes, Ref, Unaligned};
+//! use zerocopy::byteorder::network_endian::U16;
+//!
+//! #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+//! #[repr(C)]
+//! struct UdpHeader {
+//!     src_port: U16,
+//!     dst_port: U16,
+//!     length: U16,
+//!     checksum: U16,
+//! }
+//!
+//! struct UdpPacket<B: ByteSlice> {
+//!     header: Ref<B, UdpHeader>,
+//!     body: B,
+//! }
+//!
+//! impl<B: ByteSlice> UdpPacket<B> {
+//!     fn parse(bytes: B) -> Option<UdpPacket<B>> {
+//!         let (header, body) = Ref::new_from_prefix(bytes)?;
+//!         Some(UdpPacket { header, body })
+//!     }
+//!
+//!     fn src_port(&self) -> u16 {
+//!         self.header.src_port.get()
+//!     }
+//!
+//!     // more getters...
+//! }
+//! # }
+//! ```
+
+use core::{
+    convert::{TryFrom, TryInto},
+    fmt::{self, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex},
+    marker::PhantomData,
+    num::TryFromIntError,
+};
+
+// We don't reexport `WriteBytesExt` or `ReadBytesExt` because those are only
+// available with the `std` feature enabled, and zerocopy is `no_std` by
+// default.
+pub use ::byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, NetworkEndian, BE, LE};
+
+use super::*;
+
+macro_rules! impl_fmt_trait {
+    ($name:ident, $native:ident, $trait:ident) => {
+        impl<O: ByteOrder> $trait for $name<O> {
+            #[inline(always)]
+            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+                $trait::fmt(&self.get(), f)
+            }
+        }
+    };
+}
+
+macro_rules! impl_fmt_traits {
+    ($name:ident, $native:ident, "floating point number") => {
+        impl_fmt_trait!($name, $native, Display);
+    };
+    ($name:ident, $native:ident, "unsigned integer") => {
+        impl_fmt_traits!($name, $native, @all_types);
+    };
+    ($name:ident, $native:ident, "signed integer") => {
+        impl_fmt_traits!($name, $native, @all_types);
+    };
+    ($name:ident, $native:ident, @all_types) => {
+        impl_fmt_trait!($name, $native, Display);
+        impl_fmt_trait!($name, $native, Octal);
+        impl_fmt_trait!($name, $native, LowerHex);
+        impl_fmt_trait!($name, $native, UpperHex);
+        impl_fmt_trait!($name, $native, Binary);
+    };
+}
+
+macro_rules! impl_ops_traits {
+    ($name:ident, $native:ident, "floating point number") => {
+        impl_ops_traits!($name, $native, @all_types);
+        impl_ops_traits!($name, $native, @signed_integer_floating_point);
+    };
+    ($name:ident, $native:ident, "unsigned integer") => {
+        impl_ops_traits!($name, $native, @signed_unsigned_integer);
+        impl_ops_traits!($name, $native, @all_types);
+    };
+    ($name:ident, $native:ident, "signed integer") => {
+        impl_ops_traits!($name, $native, @signed_unsigned_integer);
+        impl_ops_traits!($name, $native, @signed_integer_floating_point);
+        impl_ops_traits!($name, $native, @all_types);
+    };
+    ($name:ident, $native:ident, @signed_unsigned_integer) => {
+        impl_ops_traits!(@without_byteorder_swap $name, $native, BitAnd, bitand, BitAndAssign, bitand_assign);
+        impl_ops_traits!(@without_byteorder_swap $name, $native, BitOr, bitor, BitOrAssign, bitor_assign);
+        impl_ops_traits!(@without_byteorder_swap $name, $native, BitXor, bitxor, BitXorAssign, bitxor_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Shl, shl, ShlAssign, shl_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Shr, shr, ShrAssign, shr_assign);
+
+        impl<O> core::ops::Not for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn not(self) -> $name<O> {
+                 let self_native = $native::from_ne_bytes(self.0);
+                 $name((!self_native).to_ne_bytes(), PhantomData)
+            }
+        }
+    };
+    ($name:ident, $native:ident, @signed_integer_floating_point) => {
+        impl<O: ByteOrder> core::ops::Neg for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn neg(self) -> $name<O> {
+                let self_native: $native = self.get();
+                #[allow(clippy::arithmetic_side_effects)]
+                $name::<O>::new(-self_native)
+            }
+        }
+    };
+    ($name:ident, $native:ident, @all_types) => {
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Add, add, AddAssign, add_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Div, div, DivAssign, div_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Mul, mul, MulAssign, mul_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Rem, rem, RemAssign, rem_assign);
+        impl_ops_traits!(@with_byteorder_swap $name, $native, Sub, sub, SubAssign, sub_assign);
+    };
+    (@with_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
+        impl<O: ByteOrder> core::ops::$trait for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                let self_native: $native = self.get();
+                let rhs_native: $native = rhs.get();
+                let result_native = core::ops::$trait::$method(self_native, rhs_native);
+                $name::<O>::new(result_native)
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign for $name<O> {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                *self = core::ops::$trait::$method(*self, rhs);
+            }
+        }
+    };
+    // Implement traits in terms of the same trait on the native type, but
+    // without performing a byte order swap. This only works for bitwise
+    // operations like `&`, `|`, etc.
+    (@without_byteorder_swap $name:ident, $native:ident, $trait:ident, $method:ident, $trait_assign:ident, $method_assign:ident) => {
+        impl<O: ByteOrder> core::ops::$trait for $name<O> {
+            type Output = $name<O>;
+
+            #[inline(always)]
+            fn $method(self, rhs: $name<O>) -> $name<O> {
+                let self_native = $native::from_ne_bytes(self.0);
+                let rhs_native = $native::from_ne_bytes(rhs.0);
+                let result_native = core::ops::$trait::$method(self_native, rhs_native);
+                $name(result_native.to_ne_bytes(), PhantomData)
+            }
+        }
+
+        impl<O: ByteOrder> core::ops::$trait_assign for $name<O> {
+            #[inline(always)]
+            fn $method_assign(&mut self, rhs: $name<O>) {
+                *self = core::ops::$trait::$method(*self, rhs);
+            }
+        }
+    };
+}
+
+macro_rules! doc_comment {
+    ($x:expr, $($tt:tt)*) => {
+        #[doc = $x]
+        $($tt)*
+    };
+}
+
+macro_rules! define_max_value_constant {
+    ($name:ident, $bytes:expr, "unsigned integer") => {
+        /// The maximum value.
+        ///
+        /// This constant should be preferred to constructing a new value using
+        /// `new`, as `new` may perform an endianness swap depending on the
+        /// endianness `O` and the endianness of the platform.
+        pub const MAX_VALUE: $name<O> = $name([0xFFu8; $bytes], PhantomData);
+    };
+    // We don't provide maximum and minimum value constants for signed values
+    // and floats because there's no way to do it generically - it would require
+    // a different value depending on the value of the `ByteOrder` type
+    // parameter. Currently, one workaround would be to provide implementations
+    // for concrete implementations of that trait. In the long term, if we are
+    // ever able to make the `new` constructor a const fn, we could use that
+    // instead.
+    ($name:ident, $bytes:expr, "signed integer") => {};
+    ($name:ident, $bytes:expr, "floating point number") => {};
+}
+
+macro_rules! define_type {
+    ($article:ident,
+        $name:ident,
+        $native:ident,
+        $bits:expr,
+        $bytes:expr,
+        $read_method:ident,
+        $write_method:ident,
+        $number_kind:tt,
+        [$($larger_native:ty),*],
+        [$($larger_native_try:ty),*],
+        [$($larger_byteorder:ident),*],
+        [$($larger_byteorder_try:ident),*]) => {
+        doc_comment! {
+            concat!("A ", stringify!($bits), "-bit ", $number_kind,
+            " stored in a given byte order.
+
+`", stringify!($name), "` is like the native `", stringify!($native), "` type with
+two major differences: First, it has no alignment requirement (its alignment is 1).
+Second, the endianness of its memory layout is given by the type parameter `O`,
+which can be any type which implements [`ByteOrder`]. In particular, this refers
+to [`BigEndian`], [`LittleEndian`], [`NativeEndian`], and [`NetworkEndian`].
+
+", stringify!($article), " `", stringify!($name), "` can be constructed using
+the [`new`] method, and its contained value can be obtained as a native
+`",stringify!($native), "` using the [`get`] method, or updated in place with
+the [`set`] method. In all cases, if the endianness `O` is not the same as the
+endianness of the current platform, an endianness swap will be performed in
+order to uphold the invariants that a) the layout of `", stringify!($name), "`
+has endianness `O` and that, b) the layout of `", stringify!($native), "` has
+the platform's native endianness.
+
+`", stringify!($name), "` implements [`FromBytes`], [`AsBytes`], and [`Unaligned`],
+making it useful for parsing and serialization. See the module documentation for an
+example of how it can be used for parsing UDP packets.
+
+[`new`]: crate::byteorder::", stringify!($name), "::new
+[`get`]: crate::byteorder::", stringify!($name), "::get
+[`set`]: crate::byteorder::", stringify!($name), "::set
+[`FromBytes`]: crate::FromBytes
+[`AsBytes`]: crate::AsBytes
+[`Unaligned`]: crate::Unaligned"),
+            #[derive(Copy, Clone, Eq, PartialEq, Hash)]
+            #[cfg_attr(any(feature = "derive", test), derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned))]
+            #[repr(transparent)]
+            pub struct $name<O>([u8; $bytes], PhantomData<O>);
+        }
+
+        #[cfg(not(any(feature = "derive", test)))]
+        impl_known_layout!(O => $name<O>);
+
+        safety_comment! {
+            /// SAFETY:
+            /// `$name<O>` is `repr(transparent)`, and so it has the same layout
+            /// as its only non-zero field, which is a `u8` array. `u8` arrays
+            /// are `FromZeroes`, `FromBytes`, `AsBytes`, and `Unaligned`.
+            impl_or_verify!(O => FromZeroes for $name<O>);
+            impl_or_verify!(O => FromBytes for $name<O>);
+            impl_or_verify!(O => AsBytes for $name<O>);
+            impl_or_verify!(O => Unaligned for $name<O>);
+        }
+
+        impl<O> Default for $name<O> {
+            #[inline(always)]
+            fn default() -> $name<O> {
+                $name::ZERO
+            }
+        }
+
+        impl<O> $name<O> {
+            /// The value zero.
+            ///
+            /// This constant should be preferred to constructing a new value
+            /// using `new`, as `new` may perform an endianness swap depending
+            /// on the endianness and platform.
+            pub const ZERO: $name<O> = $name([0u8; $bytes], PhantomData);
+
+            define_max_value_constant!($name, $bytes, $number_kind);
+
+            /// Constructs a new value from bytes which are already in the
+            /// endianness `O`.
+            #[inline(always)]
+            pub const fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
+                $name(bytes, PhantomData)
+            }
+        }
+
+        impl<O: ByteOrder> $name<O> {
+            // TODO(joshlf): Make these const fns if the `ByteOrder` methods
+            // ever become const fns.
+
+            /// Constructs a new value, possibly performing an endianness swap
+            /// to guarantee that the returned value has endianness `O`.
+            #[inline(always)]
+            pub fn new(n: $native) -> $name<O> {
+                let mut out = $name::default();
+                O::$write_method(&mut out.0[..], n);
+                out
+            }
+
+            /// Returns the value as a primitive type, possibly performing an
+            /// endianness swap to guarantee that the return value has the
+            /// endianness of the native platform.
+            #[inline(always)]
+            pub fn get(self) -> $native {
+                O::$read_method(&self.0[..])
+            }
+
+            /// Updates the value in place as a primitive type, possibly
+            /// performing an endianness swap to guarantee that the stored value
+            /// has the endianness `O`.
+            #[inline(always)]
+            pub fn set(&mut self, n: $native) {
+                O::$write_method(&mut self.0[..], n);
+            }
+        }
+
+        // The reasoning behind which traits to implement here is to only
+        // implement traits which won't cause inference issues. Notably,
+        // comparison traits like PartialEq and PartialOrd tend to cause
+        // inference issues.
+
+        impl<O: ByteOrder> From<$name<O>> for [u8; $bytes] {
+            #[inline(always)]
+            fn from(x: $name<O>) -> [u8; $bytes] {
+                x.0
+            }
+        }
+
+        impl<O: ByteOrder> From<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn from(bytes: [u8; $bytes]) -> $name<O> {
+                $name(bytes, PhantomData)
+            }
+        }
+
+        impl<O: ByteOrder> From<$name<O>> for $native {
+            #[inline(always)]
+            fn from(x: $name<O>) -> $native {
+                x.get()
+            }
+        }
+
+        impl<O: ByteOrder> From<$native> for $name<O> {
+            #[inline(always)]
+            fn from(x: $native) -> $name<O> {
+                $name::new(x)
+            }
+        }
+
+        $(
+            impl<O: ByteOrder> From<$name<O>> for $larger_native {
+                #[inline(always)]
+                fn from(x: $name<O>) -> $larger_native {
+                    x.get().into()
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder> TryFrom<$larger_native_try> for $name<O> {
+                type Error = TryFromIntError;
+                #[inline(always)]
+                fn try_from(x: $larger_native_try) -> Result<$name<O>, TryFromIntError> {
+                    $native::try_from(x).map($name::new)
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder, P: ByteOrder> From<$name<O>> for $larger_byteorder<P> {
+                #[inline(always)]
+                fn from(x: $name<O>) -> $larger_byteorder<P> {
+                    $larger_byteorder::new(x.get().into())
+                }
+            }
+        )*
+
+        $(
+            impl<O: ByteOrder, P: ByteOrder> TryFrom<$larger_byteorder_try<P>> for $name<O> {
+                type Error = TryFromIntError;
+                #[inline(always)]
+                fn try_from(x: $larger_byteorder_try<P>) -> Result<$name<O>, TryFromIntError> {
+                    x.get().try_into().map($name::new)
+                }
+            }
+        )*
+
+        impl<O: ByteOrder> AsRef<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn as_ref(&self) -> &[u8; $bytes] {
+                &self.0
+            }
+        }
+
+        impl<O: ByteOrder> AsMut<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn as_mut(&mut self) -> &mut [u8; $bytes] {
+                &mut self.0
+            }
+        }
+
+        impl<O: ByteOrder> PartialEq<$name<O>> for [u8; $bytes] {
+            #[inline(always)]
+            fn eq(&self, other: &$name<O>) -> bool {
+                self.eq(&other.0)
+            }
+        }
+
+        impl<O: ByteOrder> PartialEq<[u8; $bytes]> for $name<O> {
+            #[inline(always)]
+            fn eq(&self, other: &[u8; $bytes]) -> bool {
+                self.0.eq(other)
+            }
+        }
+
+        impl_fmt_traits!($name, $native, $number_kind);
+        impl_ops_traits!($name, $native, $number_kind);
+
+        impl<O: ByteOrder> Debug for $name<O> {
+            #[inline]
+            fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+                // This results in a format like "U16(42)".
+                f.debug_tuple(stringify!($name)).field(&self.get()).finish()
+            }
+        }
+    };
+}
+
+define_type!(
+    A,
+    U16,
+    u16,
+    16,
+    2,
+    read_u16,
+    write_u16,
+    "unsigned integer",
+    [u32, u64, u128, usize],
+    [u32, u64, u128, usize],
+    [U32, U64, U128],
+    [U32, U64, U128]
+);
+define_type!(
+    A,
+    U32,
+    u32,
+    32,
+    4,
+    read_u32,
+    write_u32,
+    "unsigned integer",
+    [u64, u128],
+    [u64, u128],
+    [U64, U128],
+    [U64, U128]
+);
+define_type!(
+    A,
+    U64,
+    u64,
+    64,
+    8,
+    read_u64,
+    write_u64,
+    "unsigned integer",
+    [u128],
+    [u128],
+    [U128],
+    [U128]
+);
+define_type!(A, U128, u128, 128, 16, read_u128, write_u128, "unsigned integer", [], [], [], []);
+define_type!(
+    An,
+    I16,
+    i16,
+    16,
+    2,
+    read_i16,
+    write_i16,
+    "signed integer",
+    [i32, i64, i128, isize],
+    [i32, i64, i128, isize],
+    [I32, I64, I128],
+    [I32, I64, I128]
+);
+define_type!(
+    An,
+    I32,
+    i32,
+    32,
+    4,
+    read_i32,
+    write_i32,
+    "signed integer",
+    [i64, i128],
+    [i64, i128],
+    [I64, I128],
+    [I64, I128]
+);
+define_type!(
+    An,
+    I64,
+    i64,
+    64,
+    8,
+    read_i64,
+    write_i64,
+    "signed integer",
+    [i128],
+    [i128],
+    [I128],
+    [I128]
+);
+define_type!(An, I128, i128, 128, 16, read_i128, write_i128, "signed integer", [], [], [], []);
+define_type!(
+    An,
+    F32,
+    f32,
+    32,
+    4,
+    read_f32,
+    write_f32,
+    "floating point number",
+    [f64],
+    [],
+    [F64],
+    []
+);
+define_type!(An, F64, f64, 64, 8, read_f64, write_f64, "floating point number", [], [], [], []);
+
+macro_rules! module {
+    ($name:ident, $trait:ident, $endianness_str:expr) => {
+        /// Numeric primitives stored in
+        #[doc = $endianness_str]
+        /// byte order.
+        pub mod $name {
+            use byteorder::$trait;
+
+            module!(@ty U16,  $trait, "16-bit unsigned integer", $endianness_str);
+            module!(@ty U32,  $trait, "32-bit unsigned integer", $endianness_str);
+            module!(@ty U64,  $trait, "64-bit unsigned integer", $endianness_str);
+            module!(@ty U128, $trait, "128-bit unsigned integer", $endianness_str);
+            module!(@ty I16,  $trait, "16-bit signed integer", $endianness_str);
+            module!(@ty I32,  $trait, "32-bit signed integer", $endianness_str);
+            module!(@ty I64,  $trait, "64-bit signed integer", $endianness_str);
+            module!(@ty I128, $trait, "128-bit signed integer", $endianness_str);
+            module!(@ty F32,  $trait, "32-bit floating point number", $endianness_str);
+            module!(@ty F64,  $trait, "64-bit floating point number", $endianness_str);
+        }
+    };
+    (@ty $ty:ident, $trait:ident, $desc_str:expr, $endianness_str:expr) => {
+        /// A
+        #[doc = $desc_str]
+        /// stored in
+        #[doc = $endianness_str]
+        /// byte order.
+        pub type $ty = crate::byteorder::$ty<$trait>;
+    };
+}
+
+module!(big_endian, BigEndian, "big-endian");
+module!(little_endian, LittleEndian, "little-endian");
+module!(network_endian, NetworkEndian, "network-endian");
+module!(native_endian, NativeEndian, "native-endian");
+
+#[cfg(any(test, kani))]
+mod tests {
+    use ::byteorder::NativeEndian;
+
+    use {
+        super::*,
+        crate::{AsBytes, FromBytes, Unaligned},
+    };
+
+    #[cfg(not(kani))]
+    mod compatibility {
+        pub(super) use rand::{
+            distributions::{Distribution, Standard},
+            rngs::SmallRng,
+            Rng, SeedableRng,
+        };
+
+        pub(crate) trait Arbitrary {}
+
+        impl<T> Arbitrary for T {}
+    }
+
+    #[cfg(kani)]
+    mod compatibility {
+        pub(crate) use kani::Arbitrary;
+
+        pub(crate) struct SmallRng;
+
+        impl SmallRng {
+            pub(crate) fn seed_from_u64(_state: u64) -> Self {
+                Self
+            }
+        }
+
+        pub(crate) trait Rng {
+            fn sample<T, D: Distribution<T>>(&mut self, _distr: D) -> T
+            where
+                T: Arbitrary,
+            {
+                kani::any()
+            }
+        }
+
+        impl Rng for SmallRng {}
+
+        pub(crate) trait Distribution<T> {}
+        impl<T, U> Distribution<T> for U {}
+
+        pub(crate) struct Standard;
+    }
+
+    use compatibility::*;
+
+    // A native integer type (u16, i32, etc).
+    #[cfg_attr(kani, allow(dead_code))]
+    trait Native: Arbitrary + FromBytes + AsBytes + Copy + PartialEq + Debug {
+        const ZERO: Self;
+        const MAX_VALUE: Self;
+
+        type Distribution: Distribution<Self>;
+        const DIST: Self::Distribution;
+
+        fn rand<R: Rng>(rng: &mut R) -> Self {
+            rng.sample(Self::DIST)
+        }
+
+        fn checked_add(self, rhs: Self) -> Option<Self>;
+        fn checked_div(self, rhs: Self) -> Option<Self>;
+        fn checked_mul(self, rhs: Self) -> Option<Self>;
+        fn checked_rem(self, rhs: Self) -> Option<Self>;
+        fn checked_sub(self, rhs: Self) -> Option<Self>;
+        fn checked_shl(self, rhs: Self) -> Option<Self>;
+        fn checked_shr(self, rhs: Self) -> Option<Self>;
+
+        fn is_nan(self) -> bool;
+
+        /// For `f32` and `f64`, NaN values are not considered equal to
+        /// themselves. This method is like `assert_eq!`, but it treats NaN
+        /// values as equal.
+        fn assert_eq_or_nan(self, other: Self) {
+            let slf = (!self.is_nan()).then(|| self);
+            let other = (!other.is_nan()).then(|| other);
+            assert_eq!(slf, other);
+        }
+    }
+
+    trait ByteArray:
+        FromBytes + AsBytes + Copy + AsRef<[u8]> + AsMut<[u8]> + Debug + Default + Eq
+    {
+        /// Invert the order of the bytes in the array.
+        fn invert(self) -> Self;
+    }
+
+    trait ByteOrderType: FromBytes + AsBytes + Unaligned + Copy + Eq + Debug {
+        type Native: Native;
+        type ByteArray: ByteArray;
+
+        const ZERO: Self;
+
+        fn new(native: Self::Native) -> Self;
+        fn get(self) -> Self::Native;
+        fn set(&mut self, native: Self::Native);
+        fn from_bytes(bytes: Self::ByteArray) -> Self;
+        fn into_bytes(self) -> Self::ByteArray;
+
+        /// For `f32` and `f64`, NaN values are not considered equal to
+        /// themselves. This method is like `assert_eq!`, but it treats NaN
+        /// values as equal.
+        fn assert_eq_or_nan(self, other: Self) {
+            let slf = (!self.get().is_nan()).then(|| self);
+            let other = (!other.get().is_nan()).then(|| other);
+            assert_eq!(slf, other);
+        }
+    }
+
+    trait ByteOrderTypeUnsigned: ByteOrderType {
+        const MAX_VALUE: Self;
+    }
+
+    macro_rules! impl_byte_array {
+        ($bytes:expr) => {
+            impl ByteArray for [u8; $bytes] {
+                fn invert(mut self) -> [u8; $bytes] {
+                    self.reverse();
+                    self
+                }
+            }
+        };
+    }
+
+    impl_byte_array!(2);
+    impl_byte_array!(4);
+    impl_byte_array!(8);
+    impl_byte_array!(16);
+
+    macro_rules! impl_byte_order_type_unsigned {
+        ($name:ident, unsigned) => {
+            impl<O: ByteOrder> ByteOrderTypeUnsigned for $name<O> {
+                const MAX_VALUE: $name<O> = $name::MAX_VALUE;
+            }
+        };
+        ($name:ident, signed) => {};
+    }
+
+    macro_rules! impl_traits {
+        ($name:ident, $native:ident, $bytes:expr, $sign:ident $(, @$float:ident)?) => {
+            impl Native for $native {
+                // For some types, `0 as $native` is required (for example, when
+                // `$native` is a floating-point type; `0` is an integer), but
+                // for other types, it's a trivial cast. In all cases, Clippy
+                // thinks it's dangerous.
+                #[allow(trivial_numeric_casts, clippy::as_conversions)]
+                const ZERO: $native = 0 as $native;
+                const MAX_VALUE: $native = $native::MAX;
+
+                type Distribution = Standard;
+                const DIST: Standard = Standard;
+
+                impl_traits!(@float_dependent_methods $(@$float)?);
+            }
+
+            impl<O: ByteOrder> ByteOrderType for $name<O> {
+                type Native = $native;
+                type ByteArray = [u8; $bytes];
+
+                const ZERO: $name<O> = $name::ZERO;
+
+                fn new(native: $native) -> $name<O> {
+                    $name::new(native)
+                }
+
+                fn get(self) -> $native {
+                    $name::get(self)
+                }
+
+                fn set(&mut self, native: $native) {
+                    $name::set(self, native)
+                }
+
+                fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
+                    $name::from(bytes)
+                }
+
+                fn into_bytes(self) -> [u8; $bytes] {
+                    <[u8; $bytes]>::from(self)
+                }
+            }
+
+            impl_byte_order_type_unsigned!($name, $sign);
+        };
+        (@float_dependent_methods) => {
+            fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) }
+            fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
+            fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
+            fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
+            fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
+            fn checked_shl(self, rhs: Self) -> Option<Self> { self.checked_shl(rhs.try_into().unwrap_or(u32::MAX)) }
+            fn checked_shr(self, rhs: Self) -> Option<Self> { self.checked_shr(rhs.try_into().unwrap_or(u32::MAX)) }
+            fn is_nan(self) -> bool { false }
+        };
+        (@float_dependent_methods @float) => {
+            fn checked_add(self, rhs: Self) -> Option<Self> { Some(self + rhs) }
+            fn checked_div(self, rhs: Self) -> Option<Self> { Some(self / rhs) }
+            fn checked_mul(self, rhs: Self) -> Option<Self> { Some(self * rhs) }
+            fn checked_rem(self, rhs: Self) -> Option<Self> { Some(self % rhs) }
+            fn checked_sub(self, rhs: Self) -> Option<Self> { Some(self - rhs) }
+            fn checked_shl(self, _rhs: Self) -> Option<Self> { unimplemented!() }
+            fn checked_shr(self, _rhs: Self) -> Option<Self> { unimplemented!() }
+            fn is_nan(self) -> bool { self.is_nan() }
+        };
+    }
+
+    impl_traits!(U16, u16, 2, unsigned);
+    impl_traits!(U32, u32, 4, unsigned);
+    impl_traits!(U64, u64, 8, unsigned);
+    impl_traits!(U128, u128, 16, unsigned);
+    impl_traits!(I16, i16, 2, signed);
+    impl_traits!(I32, i32, 4, signed);
+    impl_traits!(I64, i64, 8, signed);
+    impl_traits!(I128, i128, 16, signed);
+    impl_traits!(F32, f32, 4, signed, @float);
+    impl_traits!(F64, f64, 8, signed, @float);
+
+    macro_rules! call_for_unsigned_types {
+        ($fn:ident, $byteorder:ident) => {
+            $fn::<U16<$byteorder>>();
+            $fn::<U32<$byteorder>>();
+            $fn::<U64<$byteorder>>();
+            $fn::<U128<$byteorder>>();
+        };
+    }
+
+    macro_rules! call_for_signed_types {
+        ($fn:ident, $byteorder:ident) => {
+            $fn::<I16<$byteorder>>();
+            $fn::<I32<$byteorder>>();
+            $fn::<I64<$byteorder>>();
+            $fn::<I128<$byteorder>>();
+        };
+    }
+
+    macro_rules! call_for_float_types {
+        ($fn:ident, $byteorder:ident) => {
+            $fn::<F32<$byteorder>>();
+            $fn::<F64<$byteorder>>();
+        };
+    }
+
+    macro_rules! call_for_all_types {
+        ($fn:ident, $byteorder:ident) => {
+            call_for_unsigned_types!($fn, $byteorder);
+            call_for_signed_types!($fn, $byteorder);
+            call_for_float_types!($fn, $byteorder);
+        };
+    }
+
+    #[cfg(target_endian = "big")]
+    type NonNativeEndian = LittleEndian;
+    #[cfg(target_endian = "little")]
+    type NonNativeEndian = BigEndian;
+
+    // We use a `u64` seed so that we can use `SeedableRng::seed_from_u64`.
+    // `SmallRng`'s `SeedableRng::Seed` differs by platform, so if we wanted to
+    // call `SeedableRng::from_seed`, which takes a `Seed`, we would need
+    // conditional compilation by `target_pointer_width`.
+    const RNG_SEED: u64 = 0x7A03CAE2F32B5B8F;
+
+    const RAND_ITERS: usize = if cfg!(any(miri, kani)) {
+        // The tests below which use this constant used to take a very long time
+        // on Miri, which slows down local development and CI jobs. We're not
+        // using Miri to check for the correctness of our code, but rather its
+        // soundness, and at least in the context of these particular tests, a
+        // single loop iteration is just as good for surfacing UB as multiple
+        // iterations are.
+        //
+        // As of the writing of this comment, here's one set of measurements:
+        //
+        //   $ # RAND_ITERS == 1
+        //   $ cargo miri test -- -Z unstable-options --report-time endian
+        //   test byteorder::tests::test_native_endian ... ok <0.049s>
+        //   test byteorder::tests::test_non_native_endian ... ok <0.061s>
+        //
+        //   $ # RAND_ITERS == 1024
+        //   $ cargo miri test -- -Z unstable-options --report-time endian
+        //   test byteorder::tests::test_native_endian ... ok <25.716s>
+        //   test byteorder::tests::test_non_native_endian ... ok <38.127s>
+        1
+    } else {
+        1024
+    };
+
+    #[cfg_attr(test, test)]
+    #[cfg_attr(kani, kani::proof)]
+    fn test_zero() {
+        fn test_zero<T: ByteOrderType>() {
+            assert_eq!(T::ZERO.get(), T::Native::ZERO);
+        }
+
+        call_for_all_types!(test_zero, NativeEndian);
+        call_for_all_types!(test_zero, NonNativeEndian);
+    }
+
+    #[cfg_attr(test, test)]
+    #[cfg_attr(kani, kani::proof)]
+    fn test_max_value() {
+        fn test_max_value<T: ByteOrderTypeUnsigned>() {
+            assert_eq!(T::MAX_VALUE.get(), T::Native::MAX_VALUE);
+        }
+
+        call_for_unsigned_types!(test_max_value, NativeEndian);
+        call_for_unsigned_types!(test_max_value, NonNativeEndian);
+    }
+
+    #[cfg_attr(test, test)]
+    #[cfg_attr(kani, kani::proof)]
+    fn test_endian() {
+        fn test<T: ByteOrderType>(invert: bool) {
+            let mut r = SmallRng::seed_from_u64(RNG_SEED);
+            for _ in 0..RAND_ITERS {
+                let native = T::Native::rand(&mut r);
+                let mut bytes = T::ByteArray::default();
+                bytes.as_bytes_mut().copy_from_slice(native.as_bytes());
+                if invert {
+                    bytes = bytes.invert();
+                }
+                let mut from_native = T::new(native);
+                let from_bytes = T::from_bytes(bytes);
+
+                from_native.assert_eq_or_nan(from_bytes);
+                from_native.get().assert_eq_or_nan(native);
+                from_bytes.get().assert_eq_or_nan(native);
+
+                assert_eq!(from_native.into_bytes(), bytes);
+                assert_eq!(from_bytes.into_bytes(), bytes);
+
+                let updated = T::Native::rand(&mut r);
+                from_native.set(updated);
+                from_native.get().assert_eq_or_nan(updated);
+            }
+        }
+
+        fn test_native<T: ByteOrderType>() {
+            test::<T>(false);
+        }
+
+        fn test_non_native<T: ByteOrderType>() {
+            test::<T>(true);
+        }
+
+        call_for_all_types!(test_native, NativeEndian);
+        call_for_all_types!(test_non_native, NonNativeEndian);
+    }
+
+    #[test]
+    fn test_ops_impls() {
+        // Test implementations of traits in `core::ops`. Some of these are
+        // fairly banal, but some are optimized to perform the operation without
+        // swapping byte order (namely, bit-wise operations which are identical
+        // regardless of byte order). These are important to test, and while
+        // we're testing those anyway, it's trivial to test all of the impls.
+
+        fn test<T, F, G, H>(op: F, op_native: G, op_native_checked: Option<H>)
+        where
+            T: ByteOrderType,
+            F: Fn(T, T) -> T,
+            G: Fn(T::Native, T::Native) -> T::Native,
+            H: Fn(T::Native, T::Native) -> Option<T::Native>,
+        {
+            let mut r = SmallRng::seed_from_u64(RNG_SEED);
+            for _ in 0..RAND_ITERS {
+                let n0 = T::Native::rand(&mut r);
+                let n1 = T::Native::rand(&mut r);
+                let t0 = T::new(n0);
+                let t1 = T::new(n1);
+
+                // If this operation would overflow/underflow, skip it rather
+                // than attempt to catch and recover from panics.
+                if matches!(&op_native_checked, Some(checked) if checked(n0, n1).is_none()) {
+                    continue;
+                }
+
+                let n_res = op_native(n0, n1);
+                let t_res = op(t0, t1);
+
+                // For `f32` and `f64`, NaN values are not considered equal to
+                // themselves. We store `Option<f32>`/`Option<f64>` and store
+                // NaN as `None` so they can still be compared.
+                let n_res = (!T::Native::is_nan(n_res)).then(|| n_res);
+                let t_res = (!T::Native::is_nan(t_res.get())).then(|| t_res.get());
+                assert_eq!(n_res, t_res);
+            }
+        }
+
+        macro_rules! test {
+            (@binary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{
+                test!(
+                    @inner $trait,
+                    core::ops::$trait::$method,
+                    core::ops::$trait::$method,
+                    {
+                        #[allow(unused_mut, unused_assignments)]
+                        let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>;
+                        $(
+                            op_native_checked = Some(T::Native::$checked_method);
+                        )?
+                        op_native_checked
+                    },
+                    $($call_for_macros),*
+                );
+            }};
+            (@unary $trait:ident, $method:ident $([$checked_method:ident])?, $($call_for_macros:ident),*) => {{
+                test!(
+                    @inner $trait,
+                    |slf, _rhs| core::ops::$trait::$method(slf),
+                    |slf, _rhs| core::ops::$trait::$method(slf),
+                    {
+                        #[allow(unused_mut, unused_assignments)]
+                        let mut op_native_checked = None::<fn(T::Native, T::Native) -> Option<T::Native>>;
+                        $(
+                            op_native_checked = Some(|slf, _rhs| T::Native::$checked_method(slf));
+                        )?
+                        op_native_checked
+                    },
+                    $($call_for_macros),*
+                );
+            }};
+            (@inner $trait:ident, $op:expr, $op_native:expr, $op_native_checked:expr, $($call_for_macros:ident),*) => {{
+                fn t<T: ByteOrderType + core::ops::$trait<Output = T>>()
+                where
+                    T::Native: core::ops::$trait<Output = T::Native>,
+                {
+                    test::<T, _, _, _>(
+                        $op,
+                        $op_native,
+                        $op_native_checked,
+                    );
+                }
+
+                $(
+                    $call_for_macros!(t, NativeEndian);
+                    $call_for_macros!(t, NonNativeEndian);
+                )*
+            }};
+        }
+
+        test!(@binary Add, add[checked_add], call_for_all_types);
+        test!(@binary Div, div[checked_div], call_for_all_types);
+        test!(@binary Mul, mul[checked_mul], call_for_all_types);
+        test!(@binary Rem, rem[checked_rem], call_for_all_types);
+        test!(@binary Sub, sub[checked_sub], call_for_all_types);
+
+        test!(@binary BitAnd, bitand, call_for_unsigned_types, call_for_signed_types);
+        test!(@binary BitOr, bitor, call_for_unsigned_types, call_for_signed_types);
+        test!(@binary BitXor, bitxor, call_for_unsigned_types, call_for_signed_types);
+        test!(@binary Shl, shl[checked_shl], call_for_unsigned_types, call_for_signed_types);
+        test!(@binary Shr, shr[checked_shr], call_for_unsigned_types, call_for_signed_types);
+
+        test!(@unary Not, not, call_for_signed_types, call_for_unsigned_types);
+        test!(@unary Neg, neg, call_for_signed_types, call_for_float_types);
+    }
+
+    #[test]
+    fn test_debug_impl() {
+        // Ensure that Debug applies format options to the inner value.
+        let val = U16::<LE>::new(10);
+        assert_eq!(format!("{:?}", val), "U16(10)");
+        assert_eq!(format!("{:03?}", val), "U16(010)");
+        assert_eq!(format!("{:x?}", val), "U16(a)");
+    }
+}
diff --git a/extra_versions/crates/zerocopy/src/lib.rs b/extra_versions/crates/zerocopy/src/lib.rs
new file mode 100644
index 0000000..c221de2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/lib.rs
@@ -0,0 +1,8284 @@
+// Copyright 2018 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// After updating the following doc comment, make sure to run the following
+// command to update `README.md` based on its contents:
+//
+//   ./generate-readme.sh > README.md
+
+//! *<span style="font-size: 100%; color:grey;">Want to help improve zerocopy?
+//! Fill out our [user survey][user-survey]!</span>*
+//!
+//! ***<span style="font-size: 140%">Fast, safe, <span
+//! style="color:red;">compile error</span>. Pick two.</span>***
+//!
+//! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe`
+//! so you don't have to.
+//!
+//! # Overview
+//!
+//! Zerocopy provides four core marker traits, each of which can be derived
+//! (e.g., `#[derive(FromZeroes)]`):
+//! - [`FromZeroes`] indicates that a sequence of zero bytes represents a valid
+//!   instance of a type
+//! - [`FromBytes`] indicates that a type may safely be converted from an
+//!   arbitrary byte sequence
+//! - [`AsBytes`] indicates that a type may safely be converted *to* a byte
+//!   sequence
+//! - [`Unaligned`] indicates that a type's alignment requirement is 1
+//!
+//! Types which implement a subset of these traits can then be converted to/from
+//! byte sequences with little to no runtime overhead.
+//!
+//! Zerocopy also provides byte-order aware integer types that support these
+//! conversions; see the [`byteorder`] module. These types are especially useful
+//! for network parsing.
+//!
+//! [user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options
+//!
+//! # Cargo Features
+//!
+//! - **`alloc`**   
+//!   By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled,
+//!   the `alloc` crate is added as a dependency, and some allocation-related
+//!   functionality is added.
+//!
+//! - **`byteorder`** (enabled by default)   
+//!   Adds the [`byteorder`] module and a dependency on the `byteorder` crate.
+//!   The `byteorder` module provides byte order-aware equivalents of the
+//!   multi-byte primitive numerical types. Unlike their primitive equivalents,
+//!   the types in this module have no alignment requirement and support byte
+//!   order conversions. This can be useful in handling file formats, network
+//!   packet layouts, etc which don't provide alignment guarantees and which may
+//!   use a byte order different from that of the execution platform.
+//!
+//! - **`derive`**   
+//!   Provides derives for the core marker traits via the `zerocopy-derive`
+//!   crate. These derives are re-exported from `zerocopy`, so it is not
+//!   necessary to depend on `zerocopy-derive` directly.   
+//!
+//!   However, you may experience better compile times if you instead directly
+//!   depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`,
+//!   since doing so will allow Rust to compile these crates in parallel. To do
+//!   so, do *not* enable the `derive` feature, and list both dependencies in
+//!   your `Cargo.toml` with the same leading non-zero version number; e.g:
+//!
+//!   ```toml
+//!   [dependencies]
+//!   zerocopy = "0.X"
+//!   zerocopy-derive = "0.X"
+//!   ```
+//!
+//! - **`simd`**   
+//!   When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and
+//!   `AsBytes` impls are emitted for all stable SIMD types which exist on the
+//!   target platform. Note that the layout of SIMD types is not yet stabilized,
+//!   so these impls may be removed in the future if layout changes make them
+//!   invalid. For more information, see the Unsafe Code Guidelines Reference
+//!   page on the [layout of packed SIMD vectors][simd-layout].
+//!
+//! - **`simd-nightly`**   
+//!   Enables the `simd` feature and adds support for SIMD types which are only
+//!   available on nightly. Since these types are unstable, support for any type
+//!   may be removed at any point in the future.
+//!
+//! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
+//!
+//! # Security Ethos
+//!
+//! Zerocopy is expressly designed for use in security-critical contexts. We
+//! strive to ensure that that zerocopy code is sound under Rust's current
+//! memory model, and *any future memory model*. We ensure this by:
+//! - **...not 'guessing' about Rust's semantics.**   
+//!   We annotate `unsafe` code with a precise rationale for its soundness that
+//!   cites a relevant section of Rust's official documentation. When Rust's
+//!   documented semantics are unclear, we work with the Rust Operational
+//!   Semantics Team to clarify Rust's documentation.
+//! - **...rigorously testing our implementation.**   
+//!   We run tests using [Miri], ensuring that zerocopy is sound across a wide
+//!   array of supported target platforms of varying endianness and pointer
+//!   width, and across both current and experimental memory models of Rust.
+//! - **...formally proving the correctness of our implementation.**   
+//!   We apply formal verification tools like [Kani][kani] to prove zerocopy's
+//!   correctness.
+//!
+//! For more information, see our full [soundness policy].
+//!
+//! [Miri]: https://github.com/rust-lang/miri
+//! [Kani]: https://github.com/model-checking/kani
+//! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness
+//!
+//! # Relationship to Project Safe Transmute
+//!
+//! [Project Safe Transmute] is an official initiative of the Rust Project to
+//! develop language-level support for safer transmutation. The Project consults
+//! with crates like zerocopy to identify aspects of safer transmutation that
+//! would benefit from compiler support, and has developed an [experimental,
+//! compiler-supported analysis][mcp-transmutability] which determines whether,
+//! for a given type, any value of that type may be soundly transmuted into
+//! another type. Once this functionality is sufficiently mature, zerocopy
+//! intends to replace its internal transmutability analysis (implemented by our
+//! custom derives) with the compiler-supported one. This change will likely be
+//! an implementation detail that is invisible to zerocopy's users.
+//!
+//! Project Safe Transmute will not replace the need for most of zerocopy's
+//! higher-level abstractions. The experimental compiler analysis is a tool for
+//! checking the soundness of `unsafe` code, not a tool to avoid writing
+//! `unsafe` code altogether. For the foreseeable future, crates like zerocopy
+//! will still be required in order to provide higher-level abstractions on top
+//! of the building block provided by Project Safe Transmute.
+//!
+//! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html
+//! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411
+//!
+//! # MSRV
+//!
+//! See our [MSRV policy].
+//!
+//! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv
+//!
+//! # Changelog
+//!
+//! Zerocopy uses [GitHub Releases].
+//!
+//! [GitHub Releases]: https://github.com/google/zerocopy/releases
+
+// Sometimes we want to use lints which were added after our MSRV.
+// `unknown_lints` is `warn` by default and we deny warnings in CI, so without
+// this attribute, any unknown lint would cause a CI failure when testing with
+// our MSRV.
+//
+// TODO(#1201): Remove `unexpected_cfgs`
+#![allow(unknown_lints, non_local_definitions, unexpected_cfgs)]
+#![deny(renamed_and_removed_lints)]
+#![deny(
+    anonymous_parameters,
+    deprecated_in_future,
+    late_bound_lifetime_arguments,
+    missing_copy_implementations,
+    missing_debug_implementations,
+    missing_docs,
+    path_statements,
+    patterns_in_fns_without_body,
+    rust_2018_idioms,
+    trivial_numeric_casts,
+    unreachable_pub,
+    unsafe_op_in_unsafe_fn,
+    unused_extern_crates,
+    // We intentionally choose not to deny `unused_qualifications`. When items
+    // are added to the prelude (e.g., `core::mem::size_of`), this has the
+    // consequence of making some uses trigger this lint on the latest toolchain
+    // (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`)
+    // does not work on older toolchains.
+    //
+    // We tested a more complicated fix in #1413, but ultimately decided that,
+    // since this lint is just a minor style lint, the complexity isn't worth it
+    // - it's fine to occasionally have unused qualifications slip through,
+    // especially since these do not affect our user-facing API in any way.
+    variant_size_differences
+)]
+#![cfg_attr(
+    __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS,
+    deny(fuzzy_provenance_casts, lossy_provenance_casts)
+)]
+#![deny(
+    clippy::all,
+    clippy::alloc_instead_of_core,
+    clippy::arithmetic_side_effects,
+    clippy::as_underscore,
+    clippy::assertions_on_result_states,
+    clippy::as_conversions,
+    clippy::correctness,
+    clippy::dbg_macro,
+    clippy::decimal_literal_representation,
+    clippy::get_unwrap,
+    clippy::indexing_slicing,
+    clippy::missing_inline_in_public_items,
+    clippy::missing_safety_doc,
+    clippy::obfuscated_if_else,
+    clippy::perf,
+    clippy::print_stdout,
+    clippy::std_instead_of_core,
+    clippy::style,
+    clippy::suspicious,
+    clippy::todo,
+    clippy::undocumented_unsafe_blocks,
+    clippy::unimplemented,
+    clippy::unnested_or_patterns,
+    clippy::unwrap_used,
+    clippy::use_debug
+)]
+#![deny(
+    rustdoc::bare_urls,
+    rustdoc::broken_intra_doc_links,
+    rustdoc::invalid_codeblock_attributes,
+    rustdoc::invalid_html_tags,
+    rustdoc::invalid_rust_codeblocks,
+    rustdoc::missing_crate_level_docs,
+    rustdoc::private_intra_doc_links
+)]
+// In test code, it makes sense to weight more heavily towards concise, readable
+// code over correct or debuggable code.
+#![cfg_attr(any(test, kani), allow(
+    // In tests, you get line numbers and have access to source code, so panic
+    // messages are less important. You also often unwrap a lot, which would
+    // make expect'ing instead very verbose.
+    clippy::unwrap_used,
+    // In tests, there's no harm to "panic risks" - the worst that can happen is
+    // that your test will fail, and you'll fix it. By contrast, panic risks in
+    // production code introduce the possibly of code panicking unexpectedly "in
+    // the field".
+    clippy::arithmetic_side_effects,
+    clippy::indexing_slicing,
+))]
+#![cfg_attr(not(test), no_std)]
+#![cfg_attr(
+    all(feature = "simd-nightly", any(target_arch = "x86", target_arch = "x86_64")),
+    feature(stdarch_x86_avx512)
+)]
+#![cfg_attr(
+    all(feature = "simd-nightly", target_arch = "arm"),
+    feature(stdarch_arm_dsp, stdarch_arm_neon_intrinsics)
+)]
+#![cfg_attr(
+    all(feature = "simd-nightly", any(target_arch = "powerpc", target_arch = "powerpc64")),
+    feature(stdarch_powerpc)
+)]
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
+#![cfg_attr(
+    __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS,
+    feature(layout_for_ptr, strict_provenance)
+)]
+
+// This is a hack to allow zerocopy-derive derives to work in this crate. They
+// assume that zerocopy is linked as an extern crate, so they access items from
+// it as `zerocopy::Xxx`. This makes that still work.
+#[cfg(any(feature = "derive", test))]
+extern crate self as zerocopy;
+
+#[macro_use]
+mod macros;
+
+#[cfg(feature = "byteorder")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))]
+pub mod byteorder;
+#[doc(hidden)]
+pub mod macro_util;
+mod post_monomorphization_compile_fail_tests;
+mod util;
+// TODO(#252): If we make this pub, come up with a better name.
+mod wrappers;
+
+#[cfg(feature = "byteorder")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))]
+pub use crate::byteorder::*;
+pub use crate::wrappers::*;
+
+#[cfg(any(feature = "derive", test))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
+pub use zerocopy_derive::Unaligned;
+
+// `pub use` separately here so that we can mark it `#[doc(hidden)]`.
+//
+// TODO(#29): Remove this or add a doc comment.
+#[cfg(any(feature = "derive", test))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
+#[doc(hidden)]
+pub use zerocopy_derive::KnownLayout;
+
+use core::{
+    cell::{self, RefMut},
+    cmp::Ordering,
+    fmt::{self, Debug, Display, Formatter},
+    hash::Hasher,
+    marker::PhantomData,
+    mem::{self, ManuallyDrop, MaybeUninit},
+    num::{
+        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
+        NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
+    },
+    ops::{Deref, DerefMut},
+    ptr::{self, NonNull},
+    slice,
+};
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+#[cfg(feature = "alloc")]
+use alloc::{boxed::Box, vec::Vec};
+
+#[cfg(any(feature = "alloc", kani))]
+use core::alloc::Layout;
+
+// Used by `TryFromBytes::is_bit_valid`.
+#[doc(hidden)]
+pub use crate::util::ptr::Ptr;
+
+// For each polyfill, as soon as the corresponding feature is stable, the
+// polyfill import will be unused because method/function resolution will prefer
+// the inherent method/function over a trait method/function. Thus, we suppress
+// the `unused_imports` warning.
+//
+// See the documentation on `util::polyfills` for more information.
+#[allow(unused_imports)]
+use crate::util::polyfills::NonNullExt as _;
+
+#[rustversion::nightly]
+#[cfg(all(test, not(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)))]
+const _: () = {
+    #[deprecated = "some tests may be skipped due to missing RUSTFLAGS=\"--cfg __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS\""]
+    const _WARNING: () = ();
+    #[warn(deprecated)]
+    _WARNING
+};
+
+/// The target pointer width, counted in bits.
+const POINTER_WIDTH_BITS: usize = mem::size_of::<usize>() * 8;
+
+/// The layout of a type which might be dynamically-sized.
+///
+/// `DstLayout` describes the layout of sized types, slice types, and "slice
+/// DSTs" - ie, those that are known by the type system to have a trailing slice
+/// (as distinguished from `dyn Trait` types - such types *might* have a
+/// trailing slice type, but the type system isn't aware of it).
+///
+/// # Safety
+///
+/// Unlike [`core::alloc::Layout`], `DstLayout` is only used to describe full
+/// Rust types - ie, those that satisfy the layout requirements outlined by
+/// [the reference]. Callers may assume that an instance of `DstLayout`
+/// satisfies any conditions imposed on Rust types by the reference.
+///
+/// If `layout: DstLayout` describes a type, `T`, then it is guaranteed that:
+/// - `layout.align` is equal to `T`'s alignment
+/// - If `layout.size_info` is `SizeInfo::Sized { size }`, then `T: Sized` and
+///   `size_of::<T>() == size`
+/// - If `layout.size_info` is `SizeInfo::SliceDst(slice_layout)`, then
+///   - `T` is a slice DST
+/// - The `size` of an instance of `T` with `elems` trailing slice elements is
+///   equal to `slice_layout.offset + slice_layout.elem_size * elems` rounded up
+///   to the nearest multiple of `layout.align`. Any bytes in the range
+///   `[slice_layout.offset + slice_layout.elem_size * elems, size)` are padding
+///   and must not be assumed to be initialized.
+///
+/// [the reference]: https://doc.rust-lang.org/reference/type-layout.html
+#[doc(hidden)]
+#[allow(missing_debug_implementations, missing_copy_implementations)]
+#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
+pub struct DstLayout {
+    align: NonZeroUsize,
+    size_info: SizeInfo,
+}
+
+#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
+enum SizeInfo<E = usize> {
+    Sized { _size: usize },
+    SliceDst(TrailingSliceLayout<E>),
+}
+
+#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))]
+struct TrailingSliceLayout<E = usize> {
+    // The offset of the first byte of the trailing slice field. Note that this
+    // is NOT the same as the minimum size of the type. For example, consider
+    // the following type:
+    //
+    //   struct Foo {
+    //       a: u16,
+    //       b: u8,
+    //       c: [u8],
+    //   }
+    //
+    // In `Foo`, `c` is at byte offset 3. When `c.len() == 0`, `c` is followed
+    // by a padding byte.
+    _offset: usize,
+    // The size of the element type of the trailing slice field.
+    _elem_size: E,
+}
+
+impl SizeInfo {
+    /// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a
+    /// `NonZeroUsize`. If `elem_size` is 0, returns `None`.
+    #[allow(unused)]
+    const fn try_to_nonzero_elem_size(&self) -> Option<SizeInfo<NonZeroUsize>> {
+        Some(match *self {
+            SizeInfo::Sized { _size } => SizeInfo::Sized { _size },
+            SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => {
+                if let Some(_elem_size) = NonZeroUsize::new(_elem_size) {
+                    SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size })
+                } else {
+                    return None;
+                }
+            }
+        })
+    }
+}
+
+#[doc(hidden)]
+#[derive(Copy, Clone)]
+#[cfg_attr(test, derive(Debug))]
+#[allow(missing_debug_implementations)]
+pub enum _CastType {
+    _Prefix,
+    _Suffix,
+}
+
+impl DstLayout {
+    /// The minimum possible alignment of a type.
+    const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) {
+        Some(min_align) => min_align,
+        None => unreachable!(),
+    };
+
+    /// The maximum theoretic possible alignment of a type.
+    ///
+    /// For compatibility with future Rust versions, this is defined as the
+    /// maximum power-of-two that fits into a `usize`. See also
+    /// [`DstLayout::CURRENT_MAX_ALIGN`].
+    const THEORETICAL_MAX_ALIGN: NonZeroUsize =
+        match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) {
+            Some(max_align) => max_align,
+            None => unreachable!(),
+        };
+
+    /// The current, documented max alignment of a type \[1\].
+    ///
+    /// \[1\] Per <https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers>:
+    ///
+    ///   The alignment value must be a power of two from 1 up to
+    ///   2<sup>29</sup>.
+    #[cfg(not(kani))]
+    const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) {
+        Some(max_align) => max_align,
+        None => unreachable!(),
+    };
+
+    /// Constructs a `DstLayout` for a zero-sized type with `repr_align`
+    /// alignment (or 1). If `repr_align` is provided, then it must be a power
+    /// of two.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the supplied `repr_align` is not a power of two.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe code may assume that the contract of this function is satisfied.
+    #[doc(hidden)]
+    #[inline]
+    pub const fn new_zst(repr_align: Option<NonZeroUsize>) -> DstLayout {
+        let align = match repr_align {
+            Some(align) => align,
+            None => Self::MIN_ALIGN,
+        };
+
+        assert!(align.is_power_of_two());
+
+        DstLayout { align, size_info: SizeInfo::Sized { _size: 0 } }
+    }
+
+    /// Constructs a `DstLayout` which describes `T`.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
+    #[doc(hidden)]
+    #[inline]
+    pub const fn for_type<T>() -> DstLayout {
+        // SAFETY: `align` is correct by construction. `T: Sized`, and so it is
+        // sound to initialize `size_info` to `SizeInfo::Sized { size }`; the
+        // `size` field is also correct by construction.
+        DstLayout {
+            align: match NonZeroUsize::new(mem::align_of::<T>()) {
+                Some(align) => align,
+                None => unreachable!(),
+            },
+            size_info: SizeInfo::Sized { _size: mem::size_of::<T>() },
+        }
+    }
+
+    /// Constructs a `DstLayout` which describes `[T]`.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`.
+    const fn for_slice<T>() -> DstLayout {
+        // SAFETY: The alignment of a slice is equal to the alignment of its
+        // element type, and so `align` is initialized correctly.
+        //
+        // Since this is just a slice type, there is no offset between the
+        // beginning of the type and the beginning of the slice, so it is
+        // correct to set `offset: 0`. The `elem_size` is correct by
+        // construction. Since `[T]` is a (degenerate case of a) slice DST, it
+        // is correct to initialize `size_info` to `SizeInfo::SliceDst`.
+        DstLayout {
+            align: match NonZeroUsize::new(mem::align_of::<T>()) {
+                Some(align) => align,
+                None => unreachable!(),
+            },
+            size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                _offset: 0,
+                _elem_size: mem::size_of::<T>(),
+            }),
+        }
+    }
+
+    /// Like `Layout::extend`, this creates a layout that describes a record
+    /// whose layout consists of `self` followed by `next` that includes the
+    /// necessary inter-field padding, but not any trailing padding.
+    ///
+    /// In order to match the layout of a `#[repr(C)]` struct, this method
+    /// should be invoked for each field in declaration order. To add trailing
+    /// padding, call `DstLayout::pad_to_align` after extending the layout for
+    /// all fields. If `self` corresponds to a type marked with
+    /// `repr(packed(N))`, then `repr_packed` should be set to `Some(N)`,
+    /// otherwise `None`.
+    ///
+    /// This method cannot be used to match the layout of a record with the
+    /// default representation, as that representation is mostly unspecified.
+    ///
+    /// # Safety
+    ///
+    /// If a (potentially hypothetical) valid `repr(C)` Rust type begins with
+    /// fields whose layout are `self`, and those fields are immediately
+    /// followed by a field whose layout is `field`, then unsafe code may rely
+    /// on `self.extend(field, repr_packed)` producing a layout that correctly
+    /// encompasses those two components.
+    ///
+    /// We make no guarantees to the behavior of this method if these fragments
+    /// cannot appear in a valid Rust type (e.g., the concatenation of the
+    /// layouts would lead to a size larger than `isize::MAX`).
+    #[doc(hidden)]
+    #[inline]
+    pub const fn extend(self, field: DstLayout, repr_packed: Option<NonZeroUsize>) -> Self {
+        use util::{core_layout::padding_needed_for, max, min};
+
+        // If `repr_packed` is `None`, there are no alignment constraints, and
+        // the value can be defaulted to `THEORETICAL_MAX_ALIGN`.
+        let max_align = match repr_packed {
+            Some(max_align) => max_align,
+            None => Self::THEORETICAL_MAX_ALIGN,
+        };
+
+        assert!(max_align.is_power_of_two());
+
+        // We use Kani to prove that this method is robust to future increases
+        // in Rust's maximum allowed alignment. However, if such a change ever
+        // actually occurs, we'd like to be notified via assertion failures.
+        #[cfg(not(kani))]
+        {
+            debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
+            debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
+            if let Some(repr_packed) = repr_packed {
+                debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get());
+            }
+        }
+
+        // The field's alignment is clamped by `repr_packed` (i.e., the
+        // `repr(packed(N))` attribute, if any) [1].
+        //
+        // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
+        //
+        //   The alignments of each field, for the purpose of positioning
+        //   fields, is the smaller of the specified alignment and the alignment
+        //   of the field's type.
+        let field_align = min(field.align, max_align);
+
+        // The struct's alignment is the maximum of its previous alignment and
+        // `field_align`.
+        let align = max(self.align, field_align);
+
+        let size_info = match self.size_info {
+            // If the layout is already a DST, we panic; DSTs cannot be extended
+            // with additional fields.
+            SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."),
+
+            SizeInfo::Sized { _size: preceding_size } => {
+                // Compute the minimum amount of inter-field padding needed to
+                // satisfy the field's alignment, and offset of the trailing
+                // field. [1]
+                //
+                // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
+                //
+                //   Inter-field padding is guaranteed to be the minimum
+                //   required in order to satisfy each field's (possibly
+                //   altered) alignment.
+                let padding = padding_needed_for(preceding_size, field_align);
+
+                // This will not panic (and is proven to not panic, with Kani)
+                // if the layout components can correspond to a leading layout
+                // fragment of a valid Rust type, but may panic otherwise (e.g.,
+                // combining or aligning the components would create a size
+                // exceeding `isize::MAX`).
+                let offset = match preceding_size.checked_add(padding) {
+                    Some(offset) => offset,
+                    None => panic!("Adding padding to `self`'s size overflows `usize`."),
+                };
+
+                match field.size_info {
+                    SizeInfo::Sized { _size: field_size } => {
+                        // If the trailing field is sized, the resulting layout
+                        // will be sized. Its size will be the sum of the
+                        // preceeding layout, the size of the new field, and the
+                        // size of inter-field padding between the two.
+                        //
+                        // This will not panic (and is proven with Kani to not
+                        // panic) if the layout components can correspond to a
+                        // leading layout fragment of a valid Rust type, but may
+                        // panic otherwise (e.g., combining or aligning the
+                        // components would create a size exceeding
+                        // `usize::MAX`).
+                        let size = match offset.checked_add(field_size) {
+                            Some(size) => size,
+                            None => panic!("`field` cannot be appended without the total size overflowing `usize`"),
+                        };
+                        SizeInfo::Sized { _size: size }
+                    }
+                    SizeInfo::SliceDst(TrailingSliceLayout {
+                        _offset: trailing_offset,
+                        _elem_size,
+                    }) => {
+                        // If the trailing field is dynamically sized, so too
+                        // will the resulting layout. The offset of the trailing
+                        // slice component is the sum of the offset of the
+                        // trailing field and the trailing slice offset within
+                        // that field.
+                        //
+                        // This will not panic (and is proven with Kani to not
+                        // panic) if the layout components can correspond to a
+                        // leading layout fragment of a valid Rust type, but may
+                        // panic otherwise (e.g., combining or aligning the
+                        // components would create a size exceeding
+                        // `usize::MAX`).
+                        let offset = match offset.checked_add(trailing_offset) {
+                            Some(offset) => offset,
+                            None => panic!("`field` cannot be appended without the total size overflowing `usize`"),
+                        };
+                        SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size })
+                    }
+                }
+            }
+        };
+
+        DstLayout { align, size_info }
+    }
+
+    /// Like `Layout::pad_to_align`, this routine rounds the size of this layout
+    /// up to the nearest multiple of this type's alignment or `repr_packed`
+    /// (whichever is less). This method leaves DST layouts unchanged, since the
+    /// trailing padding of DSTs is computed at runtime.
+    ///
+    /// In order to match the layout of a `#[repr(C)]` struct, this method
+    /// should be invoked after the invocations of [`DstLayout::extend`]. If
+    /// `self` corresponds to a type marked with `repr(packed(N))`, then
+    /// `repr_packed` should be set to `Some(N)`, otherwise `None`.
+    ///
+    /// This method cannot be used to match the layout of a record with the
+    /// default representation, as that representation is mostly unspecified.
+    ///
+    /// # Safety
+    ///
+    /// If a (potentially hypothetical) valid `repr(C)` type begins with fields
+    /// whose layout are `self` followed only by zero or more bytes of trailing
+    /// padding (not included in `self`), then unsafe code may rely on
+    /// `self.pad_to_align(repr_packed)` producing a layout that correctly
+    /// encapsulates the layout of that type.
+    ///
+    /// We make no guarantees to the behavior of this method if `self` cannot
+    /// appear in a valid Rust type (e.g., because the addition of trailing
+    /// padding would lead to a size larger than `isize::MAX`).
+    #[doc(hidden)]
+    #[inline]
+    pub const fn pad_to_align(self) -> Self {
+        use util::core_layout::padding_needed_for;
+
+        let size_info = match self.size_info {
+            // For sized layouts, we add the minimum amount of trailing padding
+            // needed to satisfy alignment.
+            SizeInfo::Sized { _size: unpadded_size } => {
+                let padding = padding_needed_for(unpadded_size, self.align);
+                let size = match unpadded_size.checked_add(padding) {
+                    Some(size) => size,
+                    None => panic!("Adding padding caused size to overflow `usize`."),
+                };
+                SizeInfo::Sized { _size: size }
+            }
+            // For DST layouts, trailing padding depends on the length of the
+            // trailing DST and is computed at runtime. This does not alter the
+            // offset or element size of the layout, so we leave `size_info`
+            // unchanged.
+            size_info @ SizeInfo::SliceDst(_) => size_info,
+        };
+
+        DstLayout { align: self.align, size_info }
+    }
+
+    /// Validates that a cast is sound from a layout perspective.
+    ///
+    /// Validates that the size and alignment requirements of a type with the
+    /// layout described in `self` would not be violated by performing a
+    /// `cast_type` cast from a pointer with address `addr` which refers to a
+    /// memory region of size `bytes_len`.
+    ///
+    /// If the cast is valid, `validate_cast_and_convert_metadata` returns
+    /// `(elems, split_at)`. If `self` describes a dynamically-sized type, then
+    /// `elems` is the maximum number of trailing slice elements for which a
+    /// cast would be valid (for sized types, `elem` is meaningless and should
+    /// be ignored). `split_at` is the index at which to split the memory region
+    /// in order for the prefix (suffix) to contain the result of the cast, and
+    /// in order for the remaining suffix (prefix) to contain the leftover
+    /// bytes.
+    ///
+    /// There are three conditions under which a cast can fail:
+    /// - The smallest possible value for the type is larger than the provided
+    ///   memory region
+    /// - A prefix cast is requested, and `addr` does not satisfy `self`'s
+    ///   alignment requirement
+    /// - A suffix cast is requested, and `addr + bytes_len` does not satisfy
+    ///   `self`'s alignment requirement (as a consequence, since all instances
+    ///   of the type are a multiple of its alignment, no size for the type will
+    ///   result in a starting address which is properly aligned)
+    ///
+    /// # Safety
+    ///
+    /// The caller may assume that this implementation is correct, and may rely
+    /// on that assumption for the soundness of their code. In particular, the
+    /// caller may assume that, if `validate_cast_and_convert_metadata` returns
+    /// `Some((elems, split_at))`, then:
+    /// - A pointer to the type (for dynamically sized types, this includes
+    ///   `elems` as its pointer metadata) describes an object of size `size <=
+    ///   bytes_len`
+    /// - If this is a prefix cast:
+    ///   - `addr` satisfies `self`'s alignment
+    ///   - `size == split_at`
+    /// - If this is a suffix cast:
+    ///   - `split_at == bytes_len - size`
+    ///   - `addr + split_at` satisfies `self`'s alignment
+    ///
+    /// Note that this method does *not* ensure that a pointer constructed from
+    /// its return values will be a valid pointer. In particular, this method
+    /// does not reason about `isize` overflow, which is a requirement of many
+    /// Rust pointer APIs, and may at some point be determined to be a validity
+    /// invariant of pointer types themselves. This should never be a problem so
+    /// long as the arguments to this method are derived from a known-valid
+    /// pointer (e.g., one derived from a safe Rust reference), but it is
+    /// nonetheless the caller's responsibility to justify that pointer
+    /// arithmetic will not overflow based on a safety argument *other than* the
+    /// mere fact that this method returned successfully.
+    ///
+    /// # Panics
+    ///
+    /// `validate_cast_and_convert_metadata` will panic if `self` describes a
+    /// DST whose trailing slice element is zero-sized.
+    ///
+    /// If `addr + bytes_len` overflows `usize`,
+    /// `validate_cast_and_convert_metadata` may panic, or it may return
+    /// incorrect results. No guarantees are made about when
+    /// `validate_cast_and_convert_metadata` will panic. The caller should not
+    /// rely on `validate_cast_and_convert_metadata` panicking in any particular
+    /// condition, even if `debug_assertions` are enabled.
+    #[allow(unused)]
+    const fn validate_cast_and_convert_metadata(
+        &self,
+        addr: usize,
+        bytes_len: usize,
+        cast_type: _CastType,
+    ) -> Option<(usize, usize)> {
+        // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`.
+        macro_rules! __debug_assert {
+            ($e:expr $(, $msg:expr)?) => {
+                debug_assert!({
+                    #[allow(clippy::arithmetic_side_effects)]
+                    let e = $e;
+                    e
+                } $(, $msg)?);
+            };
+        }
+
+        // Note that, in practice, `self` is always a compile-time constant. We
+        // do this check earlier than needed to ensure that we always panic as a
+        // result of bugs in the program (such as calling this function on an
+        // invalid type) instead of allowing this panic to be hidden if the cast
+        // would have failed anyway for runtime reasons (such as a too-small
+        // memory region).
+        //
+        // TODO(#67): Once our MSRV is 1.65, use let-else:
+        // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements
+        let size_info = match self.size_info.try_to_nonzero_elem_size() {
+            Some(size_info) => size_info,
+            None => panic!("attempted to cast to slice type with zero-sized element"),
+        };
+
+        // Precondition
+        __debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX");
+
+        // Alignment checks go in their own block to avoid introducing variables
+        // into the top-level scope.
+        {
+            // We check alignment for `addr` (for prefix casts) or `addr +
+            // bytes_len` (for suffix casts). For a prefix cast, the correctness
+            // of this check is trivial - `addr` is the address the object will
+            // live at.
+            //
+            // For a suffix cast, we know that all valid sizes for the type are
+            // a multiple of the alignment (and by safety precondition, we know
+            // `DstLayout` may only describe valid Rust types). Thus, a
+            // validly-sized instance which lives at a validly-aligned address
+            // must also end at a validly-aligned address. Thus, if the end
+            // address for a suffix cast (`addr + bytes_len`) is not aligned,
+            // then no valid start address will be aligned either.
+            let offset = match cast_type {
+                _CastType::_Prefix => 0,
+                _CastType::_Suffix => bytes_len,
+            };
+
+            // Addition is guaranteed not to overflow because `offset <=
+            // bytes_len`, and `addr + bytes_len <= usize::MAX` is a
+            // precondition of this method. Modulus is guaranteed not to divide
+            // by 0 because `align` is non-zero.
+            #[allow(clippy::arithmetic_side_effects)]
+            if (addr + offset) % self.align.get() != 0 {
+                return None;
+            }
+        }
+
+        let (elems, self_bytes) = match size_info {
+            SizeInfo::Sized { _size: size } => {
+                if size > bytes_len {
+                    return None;
+                }
+                (0, size)
+            }
+            SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size: elem_size }) => {
+                // Calculate the maximum number of bytes that could be consumed
+                // - any number of bytes larger than this will either not be a
+                // multiple of the alignment, or will be larger than
+                // `bytes_len`.
+                let max_total_bytes =
+                    util::round_down_to_next_multiple_of_alignment(bytes_len, self.align);
+                // Calculate the maximum number of bytes that could be consumed
+                // by the trailing slice.
+                //
+                // TODO(#67): Once our MSRV is 1.65, use let-else:
+                // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements
+                let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) {
+                    Some(max) => max,
+                    // `bytes_len` too small even for 0 trailing slice elements.
+                    None => return None,
+                };
+
+                // Calculate the number of elements that fit in
+                // `max_slice_and_padding_bytes`; any remaining bytes will be
+                // considered padding.
+                //
+                // Guaranteed not to divide by zero: `elem_size` is non-zero.
+                #[allow(clippy::arithmetic_side_effects)]
+                let elems = max_slice_and_padding_bytes / elem_size.get();
+                // Guaranteed not to overflow on multiplication: `usize::MAX >=
+                // max_slice_and_padding_bytes >= (max_slice_and_padding_bytes /
+                // elem_size) * elem_size`.
+                //
+                // Guaranteed not to overflow on addition:
+                // - max_slice_and_padding_bytes == max_total_bytes - offset
+                // - elems * elem_size <= max_slice_and_padding_bytes == max_total_bytes - offset
+                // - elems * elem_size + offset <= max_total_bytes <= usize::MAX
+                #[allow(clippy::arithmetic_side_effects)]
+                let without_padding = offset + elems * elem_size.get();
+                // `self_bytes` is equal to the offset bytes plus the bytes
+                // consumed by the trailing slice plus any padding bytes
+                // required to satisfy the alignment. Note that we have computed
+                // the maximum number of trailing slice elements that could fit
+                // in `self_bytes`, so any padding is guaranteed to be less than
+                // the size of an extra element.
+                //
+                // Guaranteed not to overflow:
+                // - By previous comment: without_padding == elems * elem_size +
+                //   offset <= max_total_bytes
+                // - By construction, `max_total_bytes` is a multiple of
+                //   `self.align`.
+                // - At most, adding padding needed to round `without_padding`
+                //   up to the next multiple of the alignment will bring
+                //   `self_bytes` up to `max_total_bytes`.
+                #[allow(clippy::arithmetic_side_effects)]
+                let self_bytes = without_padding
+                    + util::core_layout::padding_needed_for(without_padding, self.align);
+                (elems, self_bytes)
+            }
+        };
+
+        __debug_assert!(self_bytes <= bytes_len);
+
+        let split_at = match cast_type {
+            _CastType::_Prefix => self_bytes,
+            // Guaranteed not to underflow:
+            // - In the `Sized` branch, only returns `size` if `size <=
+            //   bytes_len`.
+            // - In the `SliceDst` branch, calculates `self_bytes <=
+            //   max_toatl_bytes`, which is upper-bounded by `bytes_len`.
+            #[allow(clippy::arithmetic_side_effects)]
+            _CastType::_Suffix => bytes_len - self_bytes,
+        };
+
+        Some((elems, split_at))
+    }
+}
+
+/// A trait which carries information about a type's layout that is used by the
+/// internals of this crate.
+///
+/// This trait is not meant for consumption by code outside of this crate. While
+/// the normal semver stability guarantees apply with respect to which types
+/// implement this trait and which trait implementations are implied by this
+/// trait, no semver stability guarantees are made regarding its internals; they
+/// may change at any time, and code which makes use of them may break.
+///
+/// # Safety
+///
+/// This trait does not convey any safety guarantees to code outside this crate.
+#[doc(hidden)] // TODO: Remove this once KnownLayout is used by other APIs
+pub unsafe trait KnownLayout {
+    // The `Self: Sized` bound makes it so that `KnownLayout` can still be
+    // object safe. It's not currently object safe thanks to `const LAYOUT`, and
+    // it likely won't be in the future, but there's no reason not to be
+    // forwards-compatible with object safety.
+    #[doc(hidden)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    #[doc(hidden)]
+    const LAYOUT: DstLayout;
+
+    /// SAFETY: The returned pointer has the same address and provenance as
+    /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
+    /// elements in its trailing slice. If `Self` is sized, `elems` is ignored.
+    #[doc(hidden)]
+    fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self>;
+}
+
+// SAFETY: Delegates safety to `DstLayout::for_slice`.
+unsafe impl<T: KnownLayout> KnownLayout for [T] {
+    #[allow(clippy::missing_inline_in_public_items)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized,
+    {
+    }
+    const LAYOUT: DstLayout = DstLayout::for_slice::<T>();
+
+    // SAFETY: `.cast` preserves address and provenance. The returned pointer
+    // refers to an object with `elems` elements by construction.
+    #[inline(always)]
+    fn raw_from_ptr_len(data: NonNull<u8>, elems: usize) -> NonNull<Self> {
+        // TODO(#67): Remove this allow. See NonNullExt for more details.
+        #[allow(unstable_name_collisions)]
+        NonNull::slice_from_raw_parts(data.cast::<T>(), elems)
+    }
+}
+
+#[rustfmt::skip]
+impl_known_layout!(
+    (),
+    u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64,
+    bool, char,
+    NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
+    NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize
+);
+#[rustfmt::skip]
+impl_known_layout!(
+    T         => Option<T>,
+    T: ?Sized => PhantomData<T>,
+    T         => Wrapping<T>,
+    T         => MaybeUninit<T>,
+    T: ?Sized => *const T,
+    T: ?Sized => *mut T,
+);
+impl_known_layout!(const N: usize, T => [T; N]);
+
+safety_comment! {
+    /// SAFETY:
+    /// `str` and `ManuallyDrop<[T]>` [1] have the same representations as
+    /// `[u8]` and `[T]` repsectively. `str` has different bit validity than
+    /// `[u8]`, but that doesn't affect the soundness of this impl.
+    ///
+    /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
+    ///
+    ///   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
+    ///   validity as `T`
+    ///
+    /// TODO(#429):
+    /// -  Add quotes from docs.
+    /// -  Once [1] (added in
+    /// https://github.com/rust-lang/rust/pull/115522) is available on stable,
+    /// quote the stable docs instead of the nightly docs.
+    unsafe_impl_known_layout!(#[repr([u8])] str);
+    unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop<T>);
+}
+
+/// Analyzes whether a type is [`FromZeroes`].
+///
+/// This derive analyzes, at compile time, whether the annotated type satisfies
+/// the [safety conditions] of `FromZeroes` and implements `FromZeroes` if it is
+/// sound to do so. This derive can be applied to structs, enums, and unions;
+/// e.g.:
+///
+/// ```
+/// # use zerocopy_derive::FromZeroes;
+/// #[derive(FromZeroes)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   Variant0,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// [safety conditions]: trait@FromZeroes#safety
+///
+/// # Analysis
+///
+/// *This section describes, roughly, the analysis performed by this derive to
+/// determine whether it is sound to implement `FromZeroes` for a given type.
+/// Unless you are modifying the implementation of this derive, or attempting to
+/// manually implement `FromZeroes` for a type yourself, you don't need to read
+/// this section.*
+///
+/// If a type has the following properties, then this derive can implement
+/// `FromZeroes` for that type:
+///
+/// - If the type is a struct, all of its fields must be `FromZeroes`.
+/// - If the type is an enum, it must be C-like (meaning that all variants have
+///   no fields) and it must have a variant with a discriminant of `0`. See [the
+///   reference] for a description of how discriminant values are chosen.
+/// - The type must not contain any [`UnsafeCell`]s (this is required in order
+///   for it to be sound to construct a `&[u8]` and a `&T` to the same region of
+///   memory). The type may contain references or pointers to `UnsafeCell`s so
+///   long as those values can themselves be initialized from zeroes
+///   (`FromZeroes` is not currently implemented for, e.g.,
+///   `Option<&UnsafeCell<_>>`, but it could be one day).
+///
+/// This analysis is subject to change. Unsafe code may *only* rely on the
+/// documented [safety conditions] of `FromZeroes`, and must *not* rely on the
+/// implementation details of this derive.
+///
+/// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
+/// [`UnsafeCell`]: core::cell::UnsafeCell
+///
+/// ## Why isn't an explicit representation required for structs?
+///
+/// Neither this derive, nor the [safety conditions] of `FromZeroes`, requires
+/// that structs are marked with `#[repr(C)]`.
+///
+/// Per the [Rust reference](reference),
+///
+/// > The representation of a type can change the padding between fields, but
+/// > does not change the layout of the fields themselves.
+///
+/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations
+///
+/// Since the layout of structs only consists of padding bytes and field bytes,
+/// a struct is soundly `FromZeroes` if:
+/// 1. its padding is soundly `FromZeroes`, and
+/// 2. its fields are soundly `FromZeroes`.
+///
+/// The answer to the first question is always yes: padding bytes do not have
+/// any validity constraints. A [discussion] of this question in the Unsafe Code
+/// Guidelines Working Group concluded that it would be virtually unimaginable
+/// for future versions of rustc to add validity constraints to padding bytes.
+///
+/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174
+///
+/// Whether a struct is soundly `FromZeroes` therefore solely depends on whether
+/// its fields are `FromZeroes`.
+// TODO(#146): Document why we don't require an enum to have an explicit `repr`
+// attribute.
+#[cfg(any(feature = "derive", test))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
+pub use zerocopy_derive::FromZeroes;
+
+/// Types whose validity can be checked at runtime, allowing them to be
+/// conditionally converted from byte slices.
+///
+/// WARNING: Do not implement this trait yourself! Instead, use
+/// `#[derive(TryFromBytes)]`.
+///
+/// `TryFromBytes` types can safely be deserialized from an untrusted sequence
+/// of bytes by performing a runtime check that the byte sequence contains a
+/// valid instance of `Self`.
+///
+/// `TryFromBytes` is ignorant of byte order. For byte order-aware types, see
+/// the [`byteorder`] module.
+///
+/// # What is a "valid instance"?
+///
+/// In Rust, each type has *bit validity*, which refers to the set of bit
+/// patterns which may appear in an instance of that type. It is impossible for
+/// safe Rust code to produce values which violate bit validity (ie, values
+/// outside of the "valid" set of bit patterns). If `unsafe` code produces an
+/// invalid value, this is considered [undefined behavior].
+///
+/// Rust's bit validity rules are currently being decided, which means that some
+/// types have three classes of bit patterns: those which are definitely valid,
+/// and whose validity is documented in the language; those which may or may not
+/// be considered valid at some point in the future; and those which are
+/// definitely invalid.
+///
+/// Zerocopy takes a conservative approach, and only considers a bit pattern to
+/// be valid if its validity is a documenteed guarantee provided by the
+/// language.
+///
+/// For most use cases, Rust's current guarantees align with programmers'
+/// intuitions about what ought to be valid. As a result, zerocopy's
+/// conservatism should not affect most users. One notable exception is unions,
+/// whose bit validity is very up in the air; zerocopy does not permit
+/// implementing `TryFromBytes` for any union type.
+///
+/// If you are negatively affected by lack of support for a particular type,
+/// we encourage you to let us know by [filing an issue][github-repo].
+///
+/// # Safety
+///
+/// On its own, `T: TryFromBytes` does not make any guarantees about the layout
+/// or representation of `T`. It merely provides the ability to perform a
+/// validity check at runtime via methods like [`try_from_ref`].
+///
+/// Currently, it is not possible to stably implement `TryFromBytes` other than
+/// by using `#[derive(TryFromBytes)]`. While there are `#[doc(hidden)]` items
+/// on this trait that provide well-defined safety invariants, no stability
+/// guarantees are made with respect to these items. In particular, future
+/// releases of zerocopy may make backwards-breaking changes to these items,
+/// including changes that only affect soundness, which may cause code which
+/// uses those items to silently become unsound.
+///
+/// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html
+/// [github-repo]: https://github.com/google/zerocopy
+/// [`try_from_ref`]: TryFromBytes::try_from_ref
+// TODO(#5): Update `try_from_ref` doc link once it exists
+#[doc(hidden)]
+pub unsafe trait TryFromBytes {
+    /// Does a given memory range contain a valid instance of `Self`?
+    ///
+    /// # Safety
+    ///
+    /// ## Preconditions
+    ///
+    /// The memory referenced by `candidate` may only be accessed via reads for
+    /// the duration of this method call. This prohibits writes through mutable
+    /// references and through [`UnsafeCell`]s. There may exist immutable
+    /// references to the same memory which contain `UnsafeCell`s so long as:
+    /// - Those `UnsafeCell`s exist at the same byte ranges as `UnsafeCell`s in
+    ///   `Self`. This is a bidirectional property: `Self` may not contain
+    ///   `UnsafeCell`s where other references to the same memory do not, and
+    ///   vice-versa.
+    /// - Those `UnsafeCell`s are never used to perform mutation for the
+    ///   duration of this method call.
+    ///
+    /// The memory referenced by `candidate` may not be referenced by any
+    /// mutable references even if these references are not used to perform
+    /// mutation.
+    ///
+    /// `candidate` is not required to refer to a valid `Self`. However, it must
+    /// satisfy the requirement that uninitialized bytes may only be present
+    /// where it is possible for them to be present in `Self`. This is a dynamic
+    /// property: if, at a particular byte offset, a valid enum discriminant is
+    /// set, the subsequent bytes may only have uninitialized bytes as
+    /// specificed by the corresponding enum.
+    ///
+    /// Formally, given `len = size_of_val_raw(candidate)`, at every byte
+    /// offset, `b`, in the range `[0, len)`:
+    /// - If, in all instances `s: Self` of length `len`, the byte at offset `b`
+    ///   in `s` is initialized, then the byte at offset `b` within `*candidate`
+    ///   must be initialized.
+    /// - Let `c` be the contents of the byte range `[0, b)` in `*candidate`.
+    ///   Let `S` be the subset of valid instances of `Self` of length `len`
+    ///   which contain `c` in the offset range `[0, b)`. If, for all instances
+    ///   of `s: Self` in `S`, the byte at offset `b` in `s` is initialized,
+    ///   then the byte at offset `b` in `*candidate` must be initialized.
+    ///
+    ///   Pragmatically, this means that if `*candidate` is guaranteed to
+    ///   contain an enum type at a particular offset, and the enum discriminant
+    ///   stored in `*candidate` corresponds to a valid variant of that enum
+    ///   type, then it is guaranteed that the appropriate bytes of `*candidate`
+    ///   are initialized as defined by that variant's bit validity (although
+    ///   note that the variant may contain another enum type, in which case the
+    ///   same rules apply depending on the state of its discriminant, and so on
+    ///   recursively).
+    ///
+    /// ## Postconditions
+    ///
+    /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true,
+    /// `*candidate` contains a valid `Self`.
+    ///
+    /// # Panics
+    ///
+    /// `is_bit_valid` may panic. Callers are responsible for ensuring that any
+    /// `unsafe` code remains sound even in the face of `is_bit_valid`
+    /// panicking. (We support user-defined validation routines; so long as
+    /// these routines are not required to be `unsafe`, there is no way to
+    /// ensure that these do not generate panics.)
+    ///
+    /// [`UnsafeCell`]: core::cell::UnsafeCell
+    #[doc(hidden)]
+    unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool;
+
+    /// Attempts to interpret a byte slice as a `Self`.
+    ///
+    /// `try_from_ref` validates that `bytes` contains a valid `Self`, and that
+    /// it satisfies `Self`'s alignment requirement. If it does, then `bytes` is
+    /// reinterpreted as a `Self`.
+    ///
+    /// Note that Rust's bit validity rules are still being decided. As such,
+    /// there exist types whose bit validity is ambiguous. See the
+    /// `TryFromBytes` docs for a discussion of how these cases are handled.
+    // TODO(#251): In a future in which we distinguish between `FromBytes` and
+    // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow
+    // interior mutability.
+    #[inline]
+    #[doc(hidden)] // TODO(#5): Finalize name before remove this attribute.
+    fn try_from_ref(bytes: &[u8]) -> Option<&Self>
+    where
+        Self: KnownLayout,
+    {
+        let maybe_self = Ptr::from(bytes).try_cast_into_no_leftover::<Self>()?;
+
+        // SAFETY:
+        // - Since `bytes` is an immutable reference, we know that no mutable
+        //   references exist to this memory region.
+        // - Since `[u8]` contains no `UnsafeCell`s, we know there are no
+        //   `&UnsafeCell` references to this memory region.
+        // - Since we don't permit implementing `TryFromBytes` for types which
+        //   contain `UnsafeCell`s, there are no `UnsafeCell`s in `Self`, and so
+        //   the requirement that all references contain `UnsafeCell`s at the
+        //   same offsets is trivially satisfied.
+        // - All bytes of `bytes` are initialized.
+        //
+        // This call may panic. If that happens, it doesn't cause any soundness
+        // issues, as we have not generated any invalid state which we need to
+        // fix before returning.
+        if unsafe { !Self::is_bit_valid(maybe_self) } {
+            return None;
+        }
+
+        // SAFETY:
+        // - Preconditions for `as_ref`:
+        //   - `is_bit_valid` guarantees that `*maybe_self` contains a valid
+        //     `Self`. Since `&[u8]` does not permit interior mutation, this
+        //     cannot be invalidated after this method returns.
+        //   - Since the argument and return types are immutable references,
+        //     Rust will prevent the caller from producing any mutable
+        //     references to the same memory region.
+        //   - Since `Self` is not allowed to contain any `UnsafeCell`s and the
+        //     same is true of `[u8]`, interior mutation is not possible. Thus,
+        //     no mutation is possible. For the same reason, there is no
+        //     mismatch between the two types in terms of which byte ranges are
+        //     referenced as `UnsafeCell`s.
+        // - Since interior mutation isn't possible within `Self`, there's no
+        //   way for the returned reference to be used to modify the byte range,
+        //   and thus there's no way for the returned reference to be used to
+        //   write an invalid `[u8]` which would be observable via the original
+        //   `&[u8]`.
+        Some(unsafe { maybe_self.as_ref() })
+    }
+}
+
+/// Types for which a sequence of bytes all set to zero represents a valid
+/// instance of the type.
+///
+/// Any memory region of the appropriate length which is guaranteed to contain
+/// only zero bytes can be viewed as any `FromZeroes` type with no runtime
+/// overhead. This is useful whenever memory is known to be in a zeroed state,
+/// such memory returned from some allocation routines.
+///
+/// # Implementation
+///
+/// **Do not implement this trait yourself!** Instead, use
+/// [`#[derive(FromZeroes)]`][derive] (requires the `derive` Cargo feature);
+/// e.g.:
+///
+/// ```
+/// # use zerocopy_derive::FromZeroes;
+/// #[derive(FromZeroes)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   Variant0,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// This derive performs a sophisticated, compile-time safety analysis to
+/// determine whether a type is `FromZeroes`.
+///
+/// # Safety
+///
+/// *This section describes what is required in order for `T: FromZeroes`, and
+/// what unsafe code may assume of such types. If you don't plan on implementing
+/// `FromZeroes` manually, and you don't plan on writing unsafe code that
+/// operates on `FromZeroes` types, then you don't need to read this section.*
+///
+/// If `T: FromZeroes`, then unsafe code may assume that:
+/// - It is sound to treat any initialized sequence of zero bytes of length
+///   `size_of::<T>()` as a `T`.
+/// - Given `b: &[u8]` where `b.len() == size_of::<T>()`, `b` is aligned to
+///   `align_of::<T>()`, and `b` contains only zero bytes, it is sound to
+///   construct a `t: &T` at the same address as `b`, and it is sound for both
+///   `b` and `t` to be live at the same time.
+///
+/// If a type is marked as `FromZeroes` which violates this contract, it may
+/// cause undefined behavior.
+///
+/// `#[derive(FromZeroes)]` only permits [types which satisfy these
+/// requirements][derive-analysis].
+///
+#[cfg_attr(
+    feature = "derive",
+    doc = "[derive]: zerocopy_derive::FromZeroes",
+    doc = "[derive-analysis]: zerocopy_derive::FromZeroes#analysis"
+)]
+#[cfg_attr(
+    not(feature = "derive"),
+    doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html"),
+    doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html#analysis"),
+)]
+pub unsafe trait FromZeroes {
+    // The `Self: Sized` bound makes it so that `FromZeroes` is still object
+    // safe.
+    #[doc(hidden)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// Overwrites `self` with zeroes.
+    ///
+    /// Sets every byte in `self` to 0. While this is similar to doing `*self =
+    /// Self::new_zeroed()`, it differs in that `zero` does not semantically
+    /// drop the current value and replace it with a new one - it simply
+    /// modifies the bytes of the existing value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zerocopy::FromZeroes;
+    /// # use zerocopy_derive::*;
+    /// #
+    /// #[derive(FromZeroes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let mut header = PacketHeader {
+    ///     src_port: 100u16.to_be_bytes(),
+    ///     dst_port: 200u16.to_be_bytes(),
+    ///     length: 300u16.to_be_bytes(),
+    ///     checksum: 400u16.to_be_bytes(),
+    /// };
+    ///
+    /// header.zero();
+    ///
+    /// assert_eq!(header.src_port, [0, 0]);
+    /// assert_eq!(header.dst_port, [0, 0]);
+    /// assert_eq!(header.length, [0, 0]);
+    /// assert_eq!(header.checksum, [0, 0]);
+    /// ```
+    #[inline(always)]
+    fn zero(&mut self) {
+        let slf: *mut Self = self;
+        let len = mem::size_of_val(self);
+        // SAFETY:
+        // - `self` is guaranteed by the type system to be valid for writes of
+        //   size `size_of_val(self)`.
+        // - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned
+        //   as required by `u8`.
+        // - Since `Self: FromZeroes`, the all-zeroes instance is a valid
+        //   instance of `Self.`
+        //
+        // TODO(#429): Add references to docs and quotes.
+        unsafe { ptr::write_bytes(slf.cast::<u8>(), 0, len) };
+    }
+
+    /// Creates an instance of `Self` from zeroed bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use zerocopy::FromZeroes;
+    /// # use zerocopy_derive::*;
+    /// #
+    /// #[derive(FromZeroes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let header: PacketHeader = FromZeroes::new_zeroed();
+    ///
+    /// assert_eq!(header.src_port, [0, 0]);
+    /// assert_eq!(header.dst_port, [0, 0]);
+    /// assert_eq!(header.length, [0, 0]);
+    /// assert_eq!(header.checksum, [0, 0]);
+    /// ```
+    #[inline(always)]
+    fn new_zeroed() -> Self
+    where
+        Self: Sized,
+    {
+        // SAFETY: `FromZeroes` says that the all-zeroes bit pattern is legal.
+        unsafe { mem::zeroed() }
+    }
+
+    /// Creates a `Box<Self>` from zeroed bytes.
+    ///
+    /// This function is useful for allocating large values on the heap and
+    /// zero-initializing them, without ever creating a temporary instance of
+    /// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()`
+    /// will allocate `[u8; 1048576]` directly on the heap; it does not require
+    /// storing `[u8; 1048576]` in a temporary variable on the stack.
+    ///
+    /// On systems that use a heap implementation that supports allocating from
+    /// pre-zeroed memory, using `new_box_zeroed` (or related functions) may
+    /// have performance benefits.
+    ///
+    /// Note that `Box<Self>` can be converted to `Arc<Self>` and other
+    /// container types without reallocation.
+    ///
+    /// # Panics
+    ///
+    /// Panics if allocation of `size_of::<Self>()` bytes fails.
+    #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+    #[inline]
+    fn new_box_zeroed() -> Box<Self>
+    where
+        Self: Sized,
+    {
+        // If `T` is a ZST, then return a proper boxed instance of it. There is
+        // no allocation, but `Box` does require a correct dangling pointer.
+        let layout = Layout::new::<Self>();
+        if layout.size() == 0 {
+            return Box::new(Self::new_zeroed());
+        }
+
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::<Self>() };
+        if ptr.is_null() {
+            alloc::alloc::handle_alloc_error(layout);
+        }
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            Box::from_raw(ptr)
+        }
+    }
+
+    /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes.
+    ///
+    /// This function is useful for allocating large values of `[Self]` on the
+    /// heap and zero-initializing them, without ever creating a temporary
+    /// instance of `[Self; _]` on the stack. For example,
+    /// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on
+    /// the heap; it does not require storing the slice on the stack.
+    ///
+    /// On systems that use a heap implementation that supports allocating from
+    /// pre-zeroed memory, using `new_box_slice_zeroed` may have performance
+    /// benefits.
+    ///
+    /// If `Self` is a zero-sized type, then this function will return a
+    /// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any
+    /// actual information, but its `len()` property will report the correct
+    /// value.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if `size_of::<Self>() * len` overflows.
+    /// * Panics if allocation of `size_of::<Self>() * len` bytes fails.
+    #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+    #[inline]
+    fn new_box_slice_zeroed(len: usize) -> Box<[Self]>
+    where
+        Self: Sized,
+    {
+        let size = mem::size_of::<Self>()
+            .checked_mul(len)
+            .expect("mem::size_of::<Self>() * len overflows `usize`");
+        let align = mem::align_of::<Self>();
+        // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
+        // bug in which sufficiently-large allocations (those which, when
+        // rounded up to the alignment, overflow `isize`) are not rejected,
+        // which can cause undefined behavior. See #64 for details.
+        //
+        // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
+        #[allow(clippy::as_conversions)]
+        let max_alloc = (isize::MAX as usize).saturating_sub(align);
+        assert!(size <= max_alloc);
+        // TODO(https://github.com/rust-lang/rust/issues/55724): Use
+        // `Layout::repeat` once it's stabilized.
+        let layout =
+            Layout::from_size_align(size, align).expect("total allocation size overflows `isize`");
+
+        let ptr = if layout.size() != 0 {
+            // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+            #[allow(clippy::undocumented_unsafe_blocks)]
+            let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::<Self>() };
+            if ptr.is_null() {
+                alloc::alloc::handle_alloc_error(layout);
+            }
+            ptr
+        } else {
+            // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
+            // is zero, but it does require a non-null dangling pointer for its
+            // allocation.
+            NonNull::<Self>::dangling().as_ptr()
+        };
+
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            Box::from_raw(slice::from_raw_parts_mut(ptr, len))
+        }
+    }
+
+    /// Creates a `Vec<Self>` from zeroed bytes.
+    ///
+    /// This function is useful for allocating large values of `Vec`s and
+    /// zero-initializing them, without ever creating a temporary instance of
+    /// `[Self; _]` (or many temporary instances of `Self`) on the stack. For
+    /// example, `u8::new_vec_zeroed(1048576)` will allocate directly on the
+    /// heap; it does not require storing intermediate values on the stack.
+    ///
+    /// On systems that use a heap implementation that supports allocating from
+    /// pre-zeroed memory, using `new_vec_zeroed` may have performance benefits.
+    ///
+    /// If `Self` is a zero-sized type, then this function will return a
+    /// `Vec<Self>` that has the correct `len`. Such a `Vec` cannot contain any
+    /// actual information, but its `len()` property will report the correct
+    /// value.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if `size_of::<Self>() * len` overflows.
+    /// * Panics if allocation of `size_of::<Self>() * len` bytes fails.
+    #[cfg(feature = "alloc")]
+    #[cfg_attr(doc_cfg, doc(cfg(feature = "new_vec_zeroed")))]
+    #[inline(always)]
+    fn new_vec_zeroed(len: usize) -> Vec<Self>
+    where
+        Self: Sized,
+    {
+        Self::new_box_slice_zeroed(len).into()
+    }
+}
+
+/// Analyzes whether a type is [`FromBytes`].
+///
+/// This derive analyzes, at compile time, whether the annotated type satisfies
+/// the [safety conditions] of `FromBytes` and implements `FromBytes` if it is
+/// sound to do so. This derive can be applied to structs, enums, and unions;
+/// e.g.:
+///
+/// ```
+/// # use zerocopy_derive::{FromBytes, FromZeroes};
+/// #[derive(FromZeroes, FromBytes)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes, FromBytes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E,
+/// #   V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D,
+/// #   V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C,
+/// #   V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B,
+/// #   V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A,
+/// #   V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
+/// #   V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68,
+/// #   V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77,
+/// #   V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86,
+/// #   V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95,
+/// #   V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4,
+/// #   VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3,
+/// #   VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2,
+/// #   VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1,
+/// #   VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0,
+/// #   VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF,
+/// #   VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE,
+/// #   VFF,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes, FromBytes)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// [safety conditions]: trait@FromBytes#safety
+///
+/// # Analysis
+///
+/// *This section describes, roughly, the analysis performed by this derive to
+/// determine whether it is sound to implement `FromBytes` for a given type.
+/// Unless you are modifying the implementation of this derive, or attempting to
+/// manually implement `FromBytes` for a type yourself, you don't need to read
+/// this section.*
+///
+/// If a type has the following properties, then this derive can implement
+/// `FromBytes` for that type:
+///
+/// - If the type is a struct, all of its fields must be `FromBytes`.
+/// - If the type is an enum:
+///   - It must be a C-like enum (meaning that all variants have no fields).
+///   - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`,
+///     `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`).
+///   - The maximum number of discriminants must be used (so that every possible
+///     bit pattern is a valid one). Be very careful when using the `C`,
+///     `usize`, or `isize` representations, as their size is
+///     platform-dependent.
+/// - The type must not contain any [`UnsafeCell`]s (this is required in order
+///   for it to be sound to construct a `&[u8]` and a `&T` to the same region of
+///   memory). The type may contain references or pointers to `UnsafeCell`s so
+///   long as those values can themselves be initialized from zeroes
+///   (`FromBytes` is not currently implemented for, e.g., `Option<*const
+///   UnsafeCell<_>>`, but it could be one day).
+///
+/// [`UnsafeCell`]: core::cell::UnsafeCell
+///
+/// This analysis is subject to change. Unsafe code may *only* rely on the
+/// documented [safety conditions] of `FromBytes`, and must *not* rely on the
+/// implementation details of this derive.
+///
+/// ## Why isn't an explicit representation required for structs?
+///
+/// Neither this derive, nor the [safety conditions] of `FromBytes`, requires
+/// that structs are marked with `#[repr(C)]`.
+///
+/// Per the [Rust reference](reference),
+///
+/// > The representation of a type can change the padding between fields, but
+/// > does not change the layout of the fields themselves.
+///
+/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations
+///
+/// Since the layout of structs only consists of padding bytes and field bytes,
+/// a struct is soundly `FromBytes` if:
+/// 1. its padding is soundly `FromBytes`, and
+/// 2. its fields are soundly `FromBytes`.
+///
+/// The answer to the first question is always yes: padding bytes do not have
+/// any validity constraints. A [discussion] of this question in the Unsafe Code
+/// Guidelines Working Group concluded that it would be virtually unimaginable
+/// for future versions of rustc to add validity constraints to padding bytes.
+///
+/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174
+///
+/// Whether a struct is soundly `FromBytes` therefore solely depends on whether
+/// its fields are `FromBytes`.
+// TODO(#146): Document why we don't require an enum to have an explicit `repr`
+// attribute.
+#[cfg(any(feature = "derive", test))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
+pub use zerocopy_derive::FromBytes;
+
+/// Types for which any bit pattern is valid.
+///
+/// Any memory region of the appropriate length which contains initialized bytes
+/// can be viewed as any `FromBytes` type with no runtime overhead. This is
+/// useful for efficiently parsing bytes as structured data.
+///
+/// # Implementation
+///
+/// **Do not implement this trait yourself!** Instead, use
+/// [`#[derive(FromBytes)]`][derive] (requires the `derive` Cargo feature);
+/// e.g.:
+///
+/// ```
+/// # use zerocopy_derive::{FromBytes, FromZeroes};
+/// #[derive(FromZeroes, FromBytes)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes, FromBytes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E,
+/// #   V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D,
+/// #   V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C,
+/// #   V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B,
+/// #   V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A,
+/// #   V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
+/// #   V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68,
+/// #   V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77,
+/// #   V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86,
+/// #   V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95,
+/// #   V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4,
+/// #   VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3,
+/// #   VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2,
+/// #   VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1,
+/// #   VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0,
+/// #   VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF,
+/// #   VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE,
+/// #   VFF,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(FromZeroes, FromBytes)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// This derive performs a sophisticated, compile-time safety analysis to
+/// determine whether a type is `FromBytes`.
+///
+/// # Safety
+///
+/// *This section describes what is required in order for `T: FromBytes`, and
+/// what unsafe code may assume of such types. If you don't plan on implementing
+/// `FromBytes` manually, and you don't plan on writing unsafe code that
+/// operates on `FromBytes` types, then you don't need to read this section.*
+///
+/// If `T: FromBytes`, then unsafe code may assume that:
+/// - It is sound to treat any initialized sequence of bytes of length
+///   `size_of::<T>()` as a `T`.
+/// - Given `b: &[u8]` where `b.len() == size_of::<T>()`, `b` is aligned to
+///   `align_of::<T>()` it is sound to construct a `t: &T` at the same address
+///   as `b`, and it is sound for both `b` and `t` to be live at the same time.
+///
+/// If a type is marked as `FromBytes` which violates this contract, it may
+/// cause undefined behavior.
+///
+/// `#[derive(FromBytes)]` only permits [types which satisfy these
+/// requirements][derive-analysis].
+///
+#[cfg_attr(
+    feature = "derive",
+    doc = "[derive]: zerocopy_derive::FromBytes",
+    doc = "[derive-analysis]: zerocopy_derive::FromBytes#analysis"
+)]
+#[cfg_attr(
+    not(feature = "derive"),
+    doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html"),
+    doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html#analysis"),
+)]
+pub unsafe trait FromBytes: FromZeroes {
+    // The `Self: Sized` bound makes it so that `FromBytes` is still object
+    // safe.
+    #[doc(hidden)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// Interprets the given `bytes` as a `&Self` without copying.
+    ///
+    /// If `bytes.len() != size_of::<Self>()` or `bytes` is not aligned to
+    /// `align_of::<Self>()`, this returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These bytes encode a `PacketHeader`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice();
+    ///
+    /// let header = PacketHeader::ref_from(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    /// ```
+    #[inline]
+    fn ref_from(bytes: &[u8]) -> Option<&Self>
+    where
+        Self: Sized,
+    {
+        Ref::<&[u8], Self>::new(bytes).map(Ref::into_ref)
+    }
+
+    /// Interprets the prefix of the given `bytes` as a `&Self` without copying.
+    ///
+    /// `ref_from_prefix` returns a reference to the first `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or `bytes` is not
+    /// aligned to `align_of::<Self>()`, this returns `None`.
+    ///
+    /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use
+    /// [`Ref::into_ref`] to get a `&Self` with the same lifetime.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketHeader`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let header = PacketHeader::ref_from_prefix(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    /// ```
+    #[inline]
+    fn ref_from_prefix(bytes: &[u8]) -> Option<&Self>
+    where
+        Self: Sized,
+    {
+        Ref::<&[u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_ref())
+    }
+
+    /// Interprets the suffix of the given `bytes` as a `&Self` without copying.
+    ///
+    /// `ref_from_suffix` returns a reference to the last `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or the suffix of
+    /// `bytes` is not aligned to `align_of::<Self>()`, this returns `None`.
+    ///
+    /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, use
+    /// [`Ref::into_ref`] to get a `&Self` with the same lifetime.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketTrailer {
+    ///     frame_check_sequence: [u8; 4],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketTrailer`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let trailer = PacketTrailer::ref_from_suffix(bytes).unwrap();
+    ///
+    /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]);
+    /// ```
+    #[inline]
+    fn ref_from_suffix(bytes: &[u8]) -> Option<&Self>
+    where
+        Self: Sized,
+    {
+        Ref::<&[u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_ref())
+    }
+
+    /// Interprets the given `bytes` as a `&mut Self` without copying.
+    ///
+    /// If `bytes.len() != size_of::<Self>()` or `bytes` is not aligned to
+    /// `align_of::<Self>()`, this returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These bytes encode a `PacketHeader`.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..];
+    ///
+    /// let header = PacketHeader::mut_from(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    ///
+    /// header.checksum = [0, 0];
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0]);
+    /// ```
+    #[inline]
+    fn mut_from(bytes: &mut [u8]) -> Option<&mut Self>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<&mut [u8], Self>::new(bytes).map(Ref::into_mut)
+    }
+
+    /// Interprets the prefix of the given `bytes` as a `&mut Self` without
+    /// copying.
+    ///
+    /// `mut_from_prefix` returns a reference to the first `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or `bytes` is not
+    /// aligned to `align_of::<Self>()`, this returns `None`.
+    ///
+    /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use
+    /// [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketHeader`.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
+    ///
+    /// let header = PacketHeader::mut_from_prefix(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    ///
+    /// header.checksum = [0, 0];
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 8, 9]);
+    /// ```
+    #[inline]
+    fn mut_from_prefix(bytes: &mut [u8]) -> Option<&mut Self>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<&mut [u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_mut())
+    }
+
+    /// Interprets the suffix of the given `bytes` as a `&mut Self` without copying.
+    ///
+    /// `mut_from_suffix` returns a reference to the last `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or the suffix of
+    /// `bytes` is not aligned to `align_of::<Self>()`, this returns `None`.
+    ///
+    /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then,
+    /// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketTrailer {
+    ///     frame_check_sequence: [u8; 4],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketTrailer`.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
+    ///
+    /// let trailer = PacketTrailer::mut_from_suffix(bytes).unwrap();
+    ///
+    /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]);
+    ///
+    /// trailer.frame_check_sequence = [0, 0, 0, 0];
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
+    /// ```
+    #[inline]
+    fn mut_from_suffix(bytes: &mut [u8]) -> Option<&mut Self>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<&mut [u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_mut())
+    }
+
+    /// Interprets the given `bytes` as a `&[Self]` without copying.
+    ///
+    /// If `bytes.len() % size_of::<Self>() != 0` or `bytes` is not aligned to
+    /// `align_of::<Self>()`, this returns `None`.
+    ///
+    /// If you need to convert a specific number of slice elements, see
+    /// [`slice_from_prefix`](FromBytes::slice_from_prefix) or
+    /// [`slice_from_suffix`](FromBytes::slice_from_suffix).
+    ///
+    /// # Panics
+    ///
+    /// If `Self` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These bytes encode two `Pixel`s.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice();
+    ///
+    /// let pixels = Pixel::slice_from(bytes).unwrap();
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 0, g: 1, b: 2, a: 3 },
+    ///     Pixel { r: 4, g: 5, b: 6, a: 7 },
+    /// ]);
+    /// ```
+    #[inline]
+    fn slice_from(bytes: &[u8]) -> Option<&[Self]>
+    where
+        Self: Sized,
+    {
+        Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_slice())
+    }
+
+    /// Interprets the prefix of the given `bytes` as a `&[Self]` with length
+    /// equal to `count` without copying.
+    ///
+    /// This method verifies that `bytes.len() >= size_of::<T>() * count`
+    /// and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// first `size_of::<T>() * count` bytes from `bytes` to construct a
+    /// `&[Self]`, and returns the remaining bytes to the caller. It also
+    /// ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If any of the length, alignment, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// If `T` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode two `Pixel`s.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let (pixels, rest) = Pixel::slice_from_prefix(bytes, 2).unwrap();
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 0, g: 1, b: 2, a: 3 },
+    ///     Pixel { r: 4, g: 5, b: 6, a: 7 },
+    /// ]);
+    ///
+    /// assert_eq!(rest, &[8, 9]);
+    /// ```
+    #[inline]
+    fn slice_from_prefix(bytes: &[u8], count: usize) -> Option<(&[Self], &[u8])>
+    where
+        Self: Sized,
+    {
+        Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_slice(), b))
+    }
+
+    /// Interprets the suffix of the given `bytes` as a `&[Self]` with length
+    /// equal to `count` without copying.
+    ///
+    /// This method verifies that `bytes.len() >= size_of::<T>() * count`
+    /// and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// last `size_of::<T>() * count` bytes from `bytes` to construct a
+    /// `&[Self]`, and returns the preceding bytes to the caller. It also
+    /// ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If any of the length, alignment, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// If `T` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode two `Pixel`s.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let (rest, pixels) = Pixel::slice_from_suffix(bytes, 2).unwrap();
+    ///
+    /// assert_eq!(rest, &[0, 1]);
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 2, g: 3, b: 4, a: 5 },
+    ///     Pixel { r: 6, g: 7, b: 8, a: 9 },
+    /// ]);
+    /// ```
+    #[inline]
+    fn slice_from_suffix(bytes: &[u8], count: usize) -> Option<(&[u8], &[Self])>
+    where
+        Self: Sized,
+    {
+        Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_slice()))
+    }
+
+    /// Interprets the given `bytes` as a `&mut [Self]` without copying.
+    ///
+    /// If `bytes.len() % size_of::<T>() != 0` or `bytes` is not aligned to
+    /// `align_of::<T>()`, this returns `None`.
+    ///
+    /// If you need to convert a specific number of slice elements, see
+    /// [`mut_slice_from_prefix`](FromBytes::mut_slice_from_prefix) or
+    /// [`mut_slice_from_suffix`](FromBytes::mut_slice_from_suffix).
+    ///
+    /// # Panics
+    ///
+    /// If `T` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These bytes encode two `Pixel`s.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..];
+    ///
+    /// let pixels = Pixel::mut_slice_from(bytes).unwrap();
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 0, g: 1, b: 2, a: 3 },
+    ///     Pixel { r: 4, g: 5, b: 6, a: 7 },
+    /// ]);
+    ///
+    /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]);
+    /// ```
+    #[inline]
+    fn mut_slice_from(bytes: &mut [u8]) -> Option<&mut [Self]>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_mut_slice())
+    }
+
+    /// Interprets the prefix of the given `bytes` as a `&mut [Self]` with length
+    /// equal to `count` without copying.
+    ///
+    /// This method verifies that `bytes.len() >= size_of::<T>() * count`
+    /// and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// first `size_of::<T>() * count` bytes from `bytes` to construct a
+    /// `&[Self]`, and returns the remaining bytes to the caller. It also
+    /// ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If any of the length, alignment, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// If `T` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode two `Pixel`s.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
+    ///
+    /// let (pixels, rest) = Pixel::mut_slice_from_prefix(bytes, 2).unwrap();
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 0, g: 1, b: 2, a: 3 },
+    ///     Pixel { r: 4, g: 5, b: 6, a: 7 },
+    /// ]);
+    ///
+    /// assert_eq!(rest, &[8, 9]);
+    ///
+    /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 8, 9]);
+    /// ```
+    #[inline]
+    fn mut_slice_from_prefix(bytes: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_mut_slice(), b))
+    }
+
+    /// Interprets the suffix of the given `bytes` as a `&mut [Self]` with length
+    /// equal to `count` without copying.
+    ///
+    /// This method verifies that `bytes.len() >= size_of::<T>() * count`
+    /// and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// last `size_of::<T>() * count` bytes from `bytes` to construct a
+    /// `&[Self]`, and returns the preceding bytes to the caller. It also
+    /// ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If any of the length, alignment, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// If `T` is a zero-sized type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Debug, PartialEq, Eq)]
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct Pixel {
+    ///     r: u8,
+    ///     g: u8,
+    ///     b: u8,
+    ///     a: u8,
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode two `Pixel`s.
+    /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
+    ///
+    /// let (rest, pixels) = Pixel::mut_slice_from_suffix(bytes, 2).unwrap();
+    ///
+    /// assert_eq!(rest, &[0, 1]);
+    ///
+    /// assert_eq!(pixels, &[
+    ///     Pixel { r: 2, g: 3, b: 4, a: 5 },
+    ///     Pixel { r: 6, g: 7, b: 8, a: 9 },
+    /// ]);
+    ///
+    /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
+    /// ```
+    #[inline]
+    fn mut_slice_from_suffix(bytes: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])>
+    where
+        Self: Sized + AsBytes,
+    {
+        Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_mut_slice()))
+    }
+
+    /// Reads a copy of `Self` from `bytes`.
+    ///
+    /// If `bytes.len() != size_of::<Self>()`, `read_from` returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These bytes encode a `PacketHeader`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice();
+    ///
+    /// let header = PacketHeader::read_from(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    /// ```
+    #[inline]
+    fn read_from(bytes: &[u8]) -> Option<Self>
+    where
+        Self: Sized,
+    {
+        Ref::<_, Unalign<Self>>::new_unaligned(bytes).map(|r| r.read().into_inner())
+    }
+
+    /// Reads a copy of `Self` from the prefix of `bytes`.
+    ///
+    /// `read_from_prefix` reads a `Self` from the first `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()`, it returns
+    /// `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketHeader`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let header = PacketHeader::read_from_prefix(bytes).unwrap();
+    ///
+    /// assert_eq!(header.src_port, [0, 1]);
+    /// assert_eq!(header.dst_port, [2, 3]);
+    /// assert_eq!(header.length, [4, 5]);
+    /// assert_eq!(header.checksum, [6, 7]);
+    /// ```
+    #[inline]
+    fn read_from_prefix(bytes: &[u8]) -> Option<Self>
+    where
+        Self: Sized,
+    {
+        Ref::<_, Unalign<Self>>::new_unaligned_from_prefix(bytes)
+            .map(|(r, _)| r.read().into_inner())
+    }
+
+    /// Reads a copy of `Self` from the suffix of `bytes`.
+    ///
+    /// `read_from_suffix` reads a `Self` from the last `size_of::<Self>()`
+    /// bytes of `bytes`. If `bytes.len() < size_of::<Self>()`, it returns
+    /// `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::FromBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketTrailer {
+    ///     frame_check_sequence: [u8; 4],
+    /// }
+    ///
+    /// // These are more bytes than are needed to encode a `PacketTrailer`.
+    /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice();
+    ///
+    /// let trailer = PacketTrailer::read_from_suffix(bytes).unwrap();
+    ///
+    /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]);
+    /// ```
+    #[inline]
+    fn read_from_suffix(bytes: &[u8]) -> Option<Self>
+    where
+        Self: Sized,
+    {
+        Ref::<_, Unalign<Self>>::new_unaligned_from_suffix(bytes)
+            .map(|(_, r)| r.read().into_inner())
+    }
+}
+
+/// Analyzes whether a type is [`AsBytes`].
+///
+/// This derive analyzes, at compile time, whether the annotated type satisfies
+/// the [safety conditions] of `AsBytes` and implements `AsBytes` if it is
+/// sound to do so. This derive can be applied to structs, enums, and unions;
+/// e.g.:
+///
+/// ```
+/// # use zerocopy_derive::{AsBytes};
+/// #[derive(AsBytes)]
+/// #[repr(C)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(AsBytes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   Variant,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(AsBytes)]
+/// #[repr(C)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// [safety conditions]: trait@AsBytes#safety
+///
+/// # Error Messages
+///
+/// Due to the way that the custom derive for `AsBytes` is implemented, you may
+/// get an error like this:
+///
+/// ```text
+/// error[E0277]: the trait bound `HasPadding<Foo, true>: ShouldBe<false>` is not satisfied
+///   --> lib.rs:23:10
+///    |
+///  1 | #[derive(AsBytes)]
+///    |          ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<Foo, true>`
+///    |
+///    = help: the trait `ShouldBe<VALUE>` is implemented for `HasPadding<T, VALUE>`
+/// ```
+///
+/// This error indicates that the type being annotated has padding bytes, which
+/// is illegal for `AsBytes` types. Consider reducing the alignment of some
+/// fields by using types in the [`byteorder`] module, adding explicit struct
+/// fields where those padding bytes would be, or using `#[repr(packed)]`. See
+/// the Rust Reference's page on [type layout] for more information
+/// about type layout and padding.
+///
+/// [type layout]: https://doc.rust-lang.org/reference/type-layout.html
+///
+/// # Analysis
+///
+/// *This section describes, roughly, the analysis performed by this derive to
+/// determine whether it is sound to implement `AsBytes` for a given type.
+/// Unless you are modifying the implementation of this derive, or attempting to
+/// manually implement `AsBytes` for a type yourself, you don't need to read
+/// this section.*
+///
+/// If a type has the following properties, then this derive can implement
+/// `AsBytes` for that type:
+///
+/// - If the type is a struct:
+///   - It must have a defined representation (`repr(C)`, `repr(transparent)`,
+///     or `repr(packed)`).
+///   - All of its fields must be `AsBytes`.
+///   - Its layout must have no padding. This is always true for
+///     `repr(transparent)` and `repr(packed)`. For `repr(C)`, see the layout
+///     algorithm described in the [Rust Reference].
+/// - If the type is an enum:
+///   - It must be a C-like enum (meaning that all variants have no fields).
+///   - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`,
+///     `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`).
+/// - The type must not contain any [`UnsafeCell`]s (this is required in order
+///   for it to be sound to construct a `&[u8]` and a `&T` to the same region of
+///   memory). The type may contain references or pointers to `UnsafeCell`s so
+///   long as those values can themselves be initialized from zeroes (`AsBytes`
+///   is not currently implemented for, e.g., `Option<&UnsafeCell<_>>`, but it
+///   could be one day).
+///
+/// [`UnsafeCell`]: core::cell::UnsafeCell
+///
+/// This analysis is subject to change. Unsafe code may *only* rely on the
+/// documented [safety conditions] of `FromBytes`, and must *not* rely on the
+/// implementation details of this derive.
+///
+/// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html
+#[cfg(any(feature = "derive", test))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
+pub use zerocopy_derive::AsBytes;
+
+/// Types that can be viewed as an immutable slice of initialized bytes.
+///
+/// Any `AsBytes` type can be viewed as a slice of initialized bytes of the same
+/// size. This is useful for efficiently serializing structured data as raw
+/// bytes.
+///
+/// # Implementation
+///
+/// **Do not implement this trait yourself!** Instead, use
+/// [`#[derive(AsBytes)]`][derive] (requires the `derive` Cargo feature); e.g.:
+///
+/// ```
+/// # use zerocopy_derive::AsBytes;
+/// #[derive(AsBytes)]
+/// #[repr(C)]
+/// struct MyStruct {
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(AsBytes)]
+/// #[repr(u8)]
+/// enum MyEnum {
+/// #   Variant0,
+/// # /*
+///     ...
+/// # */
+/// }
+///
+/// #[derive(AsBytes)]
+/// #[repr(C)]
+/// union MyUnion {
+/// #   variant: u8,
+/// # /*
+///     ...
+/// # */
+/// }
+/// ```
+///
+/// This derive performs a sophisticated, compile-time safety analysis to
+/// determine whether a type is `AsBytes`. See the [derive
+/// documentation][derive] for guidance on how to interpret error messages
+/// produced by the derive's analysis.
+///
+/// # Safety
+///
+/// *This section describes what is required in order for `T: AsBytes`, and
+/// what unsafe code may assume of such types. If you don't plan on implementing
+/// `AsBytes` manually, and you don't plan on writing unsafe code that
+/// operates on `AsBytes` types, then you don't need to read this section.*
+///
+/// If `T: AsBytes`, then unsafe code may assume that:
+/// - It is sound to treat any `t: T` as an immutable `[u8]` of length
+///   `size_of_val(t)`.
+/// - Given `t: &T`, it is sound to construct a `b: &[u8]` where `b.len() ==
+///   size_of_val(t)` at the same address as `t`, and it is sound for both `b`
+///   and `t` to be live at the same time.
+///
+/// If a type is marked as `AsBytes` which violates this contract, it may cause
+/// undefined behavior.
+///
+/// `#[derive(AsBytes)]` only permits [types which satisfy these
+/// requirements][derive-analysis].
+///
+#[cfg_attr(
+    feature = "derive",
+    doc = "[derive]: zerocopy_derive::AsBytes",
+    doc = "[derive-analysis]: zerocopy_derive::AsBytes#analysis"
+)]
+#[cfg_attr(
+    not(feature = "derive"),
+    doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html"),
+    doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html#analysis"),
+)]
+pub unsafe trait AsBytes {
+    // The `Self: Sized` bound makes it so that this function doesn't prevent
+    // `AsBytes` from being object safe. Note that other `AsBytes` methods
+    // prevent object safety, but those provide a benefit in exchange for object
+    // safety. If at some point we remove those methods, change their type
+    // signatures, or move them out of this trait so that `AsBytes` is object
+    // safe again, it's important that this function not prevent object safety.
+    #[doc(hidden)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+
+    /// Gets the bytes of this value.
+    ///
+    /// `as_bytes` provides access to the bytes of this value as an immutable
+    /// byte slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::AsBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let header = PacketHeader {
+    ///     src_port: [0, 1],
+    ///     dst_port: [2, 3],
+    ///     length: [4, 5],
+    ///     checksum: [6, 7],
+    /// };
+    ///
+    /// let bytes = header.as_bytes();
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
+    /// ```
+    #[inline(always)]
+    fn as_bytes(&self) -> &[u8] {
+        // Note that this method does not have a `Self: Sized` bound;
+        // `size_of_val` works for unsized values too.
+        let len = mem::size_of_val(self);
+        let slf: *const Self = self;
+
+        // SAFETY:
+        // - `slf.cast::<u8>()` is valid for reads for `len *
+        //   mem::size_of::<u8>()` many bytes because...
+        //   - `slf` is the same pointer as `self`, and `self` is a reference
+        //     which points to an object whose size is `len`. Thus...
+        //     - The entire region of `len` bytes starting at `slf` is contained
+        //       within a single allocation.
+        //     - `slf` is non-null.
+        //   - `slf` is trivially aligned to `align_of::<u8>() == 1`.
+        // - `Self: AsBytes` ensures that all of the bytes of `slf` are
+        //   initialized.
+        // - Since `slf` is derived from `self`, and `self` is an immutable
+        //   reference, the only other references to this memory region that
+        //   could exist are other immutable references, and those don't allow
+        //   mutation. `AsBytes` prohibits types which contain `UnsafeCell`s,
+        //   which are the only types for which this rule wouldn't be sufficient.
+        // - The total size of the resulting slice is no larger than
+        //   `isize::MAX` because no allocation produced by safe code can be
+        //   larger than `isize::MAX`.
+        //
+        // TODO(#429): Add references to docs and quotes.
+        unsafe { slice::from_raw_parts(slf.cast::<u8>(), len) }
+    }
+
+    /// Gets the bytes of this value mutably.
+    ///
+    /// `as_bytes_mut` provides access to the bytes of this value as a mutable
+    /// byte slice.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::AsBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// # #[derive(Eq, PartialEq, Debug)]
+    /// #[derive(AsBytes, FromZeroes, FromBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let mut header = PacketHeader {
+    ///     src_port: [0, 1],
+    ///     dst_port: [2, 3],
+    ///     length: [4, 5],
+    ///     checksum: [6, 7],
+    /// };
+    ///
+    /// let bytes = header.as_bytes_mut();
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
+    ///
+    /// bytes.reverse();
+    ///
+    /// assert_eq!(header, PacketHeader {
+    ///     src_port: [7, 6],
+    ///     dst_port: [5, 4],
+    ///     length: [3, 2],
+    ///     checksum: [1, 0],
+    /// });
+    /// ```
+    #[inline(always)]
+    fn as_bytes_mut(&mut self) -> &mut [u8]
+    where
+        Self: FromBytes,
+    {
+        // Note that this method does not have a `Self: Sized` bound;
+        // `size_of_val` works for unsized values too.
+        let len = mem::size_of_val(self);
+        let slf: *mut Self = self;
+
+        // SAFETY:
+        // - `slf.cast::<u8>()` is valid for reads and writes for `len *
+        //   mem::size_of::<u8>()` many bytes because...
+        //   - `slf` is the same pointer as `self`, and `self` is a reference
+        //     which points to an object whose size is `len`. Thus...
+        //     - The entire region of `len` bytes starting at `slf` is contained
+        //       within a single allocation.
+        //     - `slf` is non-null.
+        //   - `slf` is trivially aligned to `align_of::<u8>() == 1`.
+        // - `Self: AsBytes` ensures that all of the bytes of `slf` are
+        //   initialized.
+        // - `Self: FromBytes` ensures that no write to this memory region
+        //   could result in it containing an invalid `Self`.
+        // - Since `slf` is derived from `self`, and `self` is a mutable
+        //   reference, no other references to this memory region can exist.
+        // - The total size of the resulting slice is no larger than
+        //   `isize::MAX` because no allocation produced by safe code can be
+        //   larger than `isize::MAX`.
+        //
+        // TODO(#429): Add references to docs and quotes.
+        unsafe { slice::from_raw_parts_mut(slf.cast::<u8>(), len) }
+    }
+
+    /// Writes a copy of `self` to `bytes`.
+    ///
+    /// If `bytes.len() != size_of_val(self)`, `write_to` returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::AsBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let header = PacketHeader {
+    ///     src_port: [0, 1],
+    ///     dst_port: [2, 3],
+    ///     length: [4, 5],
+    ///     checksum: [6, 7],
+    /// };
+    ///
+    /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0];
+    ///
+    /// header.write_to(&mut bytes[..]);
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]);
+    /// ```
+    ///
+    /// If too many or too few target bytes are provided, `write_to` returns
+    /// `None` and leaves the target bytes unmodified:
+    ///
+    /// ```
+    /// # use zerocopy::AsBytes;
+    /// # let header = u128::MAX;
+    /// let mut excessive_bytes = &mut [0u8; 128][..];
+    ///
+    /// let write_result = header.write_to(excessive_bytes);
+    ///
+    /// assert!(write_result.is_none());
+    /// assert_eq!(excessive_bytes, [0u8; 128]);
+    /// ```
+    #[inline]
+    fn write_to(&self, bytes: &mut [u8]) -> Option<()> {
+        if bytes.len() != mem::size_of_val(self) {
+            return None;
+        }
+
+        bytes.copy_from_slice(self.as_bytes());
+        Some(())
+    }
+
+    /// Writes a copy of `self` to the prefix of `bytes`.
+    ///
+    /// `write_to_prefix` writes `self` to the first `size_of_val(self)` bytes
+    /// of `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::AsBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let header = PacketHeader {
+    ///     src_port: [0, 1],
+    ///     dst_port: [2, 3],
+    ///     length: [4, 5],
+    ///     checksum: [6, 7],
+    /// };
+    ///
+    /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+    ///
+    /// header.write_to_prefix(&mut bytes[..]);
+    ///
+    /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
+    /// ```
+    ///
+    /// If insufficient target bytes are provided, `write_to_prefix` returns
+    /// `None` and leaves the target bytes unmodified:
+    ///
+    /// ```
+    /// # use zerocopy::AsBytes;
+    /// # let header = u128::MAX;
+    /// let mut insufficent_bytes = &mut [0, 0][..];
+    ///
+    /// let write_result = header.write_to_suffix(insufficent_bytes);
+    ///
+    /// assert!(write_result.is_none());
+    /// assert_eq!(insufficent_bytes, [0, 0]);
+    /// ```
+    #[inline]
+    fn write_to_prefix(&self, bytes: &mut [u8]) -> Option<()> {
+        let size = mem::size_of_val(self);
+        bytes.get_mut(..size)?.copy_from_slice(self.as_bytes());
+        Some(())
+    }
+
+    /// Writes a copy of `self` to the suffix of `bytes`.
+    ///
+    /// `write_to_suffix` writes `self` to the last `size_of_val(self)` bytes of
+    /// `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use zerocopy::AsBytes;
+    /// # use zerocopy_derive::*;
+    ///
+    /// #[derive(AsBytes)]
+    /// #[repr(C)]
+    /// struct PacketHeader {
+    ///     src_port: [u8; 2],
+    ///     dst_port: [u8; 2],
+    ///     length: [u8; 2],
+    ///     checksum: [u8; 2],
+    /// }
+    ///
+    /// let header = PacketHeader {
+    ///     src_port: [0, 1],
+    ///     dst_port: [2, 3],
+    ///     length: [4, 5],
+    ///     checksum: [6, 7],
+    /// };
+    ///
+    /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+    ///
+    /// header.write_to_suffix(&mut bytes[..]);
+    ///
+    /// assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]);
+    ///
+    /// let mut insufficent_bytes = &mut [0, 0][..];
+    ///
+    /// let write_result = header.write_to_suffix(insufficent_bytes);
+    ///
+    /// assert!(write_result.is_none());
+    /// assert_eq!(insufficent_bytes, [0, 0]);
+    /// ```
+    ///
+    /// If insufficient target bytes are provided, `write_to_suffix` returns
+    /// `None` and leaves the target bytes unmodified:
+    ///
+    /// ```
+    /// # use zerocopy::AsBytes;
+    /// # let header = u128::MAX;
+    /// let mut insufficent_bytes = &mut [0, 0][..];
+    ///
+    /// let write_result = header.write_to_suffix(insufficent_bytes);
+    ///
+    /// assert!(write_result.is_none());
+    /// assert_eq!(insufficent_bytes, [0, 0]);
+    /// ```
+    #[inline]
+    fn write_to_suffix(&self, bytes: &mut [u8]) -> Option<()> {
+        let start = bytes.len().checked_sub(mem::size_of_val(self))?;
+        bytes
+            .get_mut(start..)
+            .expect("`start` should be in-bounds of `bytes`")
+            .copy_from_slice(self.as_bytes());
+        Some(())
+    }
+}
+
+/// Types with no alignment requirement.
+///
+/// WARNING: Do not implement this trait yourself! Instead, use
+/// `#[derive(Unaligned)]` (requires the `derive` Cargo feature).
+///
+/// If `T: Unaligned`, then `align_of::<T>() == 1`.
+///
+/// # Safety
+///
+/// *This section describes what is required in order for `T: Unaligned`, and
+/// what unsafe code may assume of such types. `#[derive(Unaligned)]` only
+/// permits types which satisfy these requirements. If you don't plan on
+/// implementing `Unaligned` manually, and you don't plan on writing unsafe code
+/// that operates on `Unaligned` types, then you don't need to read this
+/// section.*
+///
+/// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a
+/// reference to `T` at any memory location regardless of alignment. If a type
+/// is marked as `Unaligned` which violates this contract, it may cause
+/// undefined behavior.
+pub unsafe trait Unaligned {
+    // The `Self: Sized` bound makes it so that `Unaligned` is still object
+    // safe.
+    #[doc(hidden)]
+    fn only_derive_is_allowed_to_implement_this_trait()
+    where
+        Self: Sized;
+}
+
+safety_comment! {
+    /// SAFETY:
+    /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
+    /// zero-sized type to have a size of 0 and an alignment of 1."
+    /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There
+    ///   is only one possible sequence of 0 bytes, and `()` is inhabited.
+    /// - `AsBytes`: Since `()` has size 0, it contains no padding bytes.
+    /// - `Unaligned`: `()` has alignment 1.
+    ///
+    /// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout
+    unsafe_impl!((): TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+    assert_unaligned!(());
+}
+
+safety_comment! {
+    /// SAFETY:
+    /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: all bit
+    ///   patterns are valid for numeric types [1]
+    /// - `AsBytes`: numeric types have no padding bytes [1]
+    /// - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size
+    ///   of `u8` and `i8` as 1 byte. We also know that:
+    ///   - Alignment is >= 1 [3]
+    ///   - Size is an integer multiple of alignment [4]
+    ///   - The only value >= 1 for which 1 is an integer multiple is 1
+    ///   Therefore, the only possible alignment for `u8` and `i8` is 1.
+    ///
+    /// [1] Per https://doc.rust-lang.org/beta/reference/types/numeric.html#bit-validity:
+    ///
+    ///     For every numeric type, `T`, the bit validity of `T` is equivalent to
+    ///     the bit validity of `[u8; size_of::<T>()]`. An uninitialized byte is
+    ///     not a valid `u8`.
+    ///
+    /// TODO(https://github.com/rust-lang/reference/pull/1392): Once this text
+    /// is available on the Stable docs, cite those instead.
+    ///
+    /// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout
+    ///
+    /// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
+    ///
+    ///     Alignment is measured in bytes, and must be at least 1.
+    ///
+    /// [4] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
+    ///
+    ///     The size of a value is always a multiple of its alignment.
+    ///
+    /// TODO(#278): Once we've updated the trait docs to refer to `u8`s rather
+    /// than bits or bytes, update this comment, especially the reference to
+    /// [1].
+    unsafe_impl!(u8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+    unsafe_impl!(i8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+    assert_unaligned!(u8, i8);
+    unsafe_impl!(u16: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(i16: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(u32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(i32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(u64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(i64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(u128: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(i128: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(usize: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(isize: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(f32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(f64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+}
+
+safety_comment! {
+    /// SAFETY:
+    /// - `FromZeroes`: Valid since "[t]he value false has the bit pattern
+    ///   0x00" [1].
+    /// - `AsBytes`: Since "the boolean type has a size and alignment of 1 each"
+    ///   and "The value false has the bit pattern 0x00 and the value true has
+    ///   the bit pattern 0x01" [1]. Thus, the only byte of the bool is always
+    ///   initialized.
+    /// - `Unaligned`: Per the reference [1], "[a]n object with the boolean type
+    ///   has a size and alignment of 1 each."
+    ///
+    /// [1] https://doc.rust-lang.org/reference/types/boolean.html
+    unsafe_impl!(bool: FromZeroes, AsBytes, Unaligned);
+    assert_unaligned!(bool);
+    /// SAFETY:
+    /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
+    ///   closure:
+    ///   - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object
+    ///     of the same size as that referred to by `t`. This is true because
+    ///     `bool` and `u8` have the same size (1 byte) [1].
+    ///   - Since the closure takes a `&u8` argument, given a `Ptr<'a, bool>`
+    ///     which satisfies the preconditions of
+    ///     `TryFromBytes::<bool>::is_bit_valid`, it must be guaranteed that the
+    ///     memory referenced by that `Ptr` always contains a valid `u8`. Since
+    ///     `bool`'s single byte is always initialized, `is_bit_valid`'s
+    ///     precondition requires that the same is true of its argument. Since
+    ///     `u8`'s only bit validity invariant is that its single byte must be
+    ///     initialized, this memory is guaranteed to contain a valid `u8`.
+    ///   - The alignment of `bool` is equal to the alignment of `u8`. [1] [2]
+    ///   - The impl must only return `true` for its argument if the original
+    ///     `Ptr<bool>` refers to a valid `bool`. We only return true if the
+    ///     `u8` value is 0 or 1, and both of these are valid values for `bool`.
+    ///     [3]
+    ///
+    /// [1] Per https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout:
+    ///
+    ///   The size of most primitives is given in this table.
+    ///
+    ///   | Type      | `size_of::<Type>() ` |
+    ///   |-----------|----------------------|
+    ///   | `bool`    | 1                    |
+    ///   | `u8`/`i8` | 1                    |
+    ///
+    /// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
+    ///
+    ///   The size of a value is always a multiple of its alignment.
+    ///
+    /// [3] Per https://doc.rust-lang.org/reference/types/boolean.html:
+    ///
+    ///   The value false has the bit pattern 0x00 and the value true has the
+    ///   bit pattern 0x01.
+    unsafe_impl!(bool: TryFromBytes; |byte: &u8| *byte < 2);
+}
+safety_comment! {
+    /// SAFETY:
+    /// - `FromZeroes`: Per reference [1], "[a] value of type char is a Unicode
+    ///   scalar value (i.e. a code point that is not a surrogate), represented
+    ///   as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to
+    ///   0x10FFFF range" which contains 0x0000.
+    /// - `AsBytes`: `char` is per reference [1] "represented as a 32-bit
+    ///   unsigned word" (`u32`) which is `AsBytes`. Note that unlike `u32`, not
+    ///   all bit patterns are valid for `char`.
+    ///
+    /// [1] https://doc.rust-lang.org/reference/types/textual.html
+    unsafe_impl!(char: FromZeroes, AsBytes);
+    /// SAFETY:
+    /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
+    ///   closure:
+    ///   - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object
+    ///     of the same size as that referred to by `t`. This is true because
+    ///     `char` and `u32` have the same size [1].
+    ///   - Since the closure takes a `&u32` argument, given a `Ptr<'a, char>`
+    ///     which satisfies the preconditions of
+    ///     `TryFromBytes::<char>::is_bit_valid`, it must be guaranteed that the
+    ///     memory referenced by that `Ptr` always contains a valid `u32`. Since
+    ///     `char`'s bytes are always initialized [2], `is_bit_valid`'s
+    ///     precondition requires that the same is true of its argument. Since
+    ///     `u32`'s only bit validity invariant is that its bytes must be
+    ///     initialized, this memory is guaranteed to contain a valid `u32`.
+    ///   - The alignment of `char` is equal to the alignment of `u32`. [1]
+    ///   - The impl must only return `true` for its argument if the original
+    ///     `Ptr<char>` refers to a valid `char`. `char::from_u32` guarantees
+    ///     that it returns `None` if its input is not a valid `char`. [3]
+    ///
+    /// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity:
+    ///
+    ///   `char` is guaranteed to have the same size and alignment as `u32` on
+    ///   all platforms.
+    ///
+    /// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
+    ///
+    ///   Every byte of a `char` is guaranteed to be initialized.
+    ///
+    /// [3] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
+    ///
+    ///   `from_u32()` will return `None` if the input is not a valid value for
+    ///   a `char`.
+    unsafe_impl!(char: TryFromBytes; |candidate: &u32| char::from_u32(*candidate).is_some());
+}
+safety_comment! {
+    /// SAFETY:
+    /// - `FromZeroes`, `AsBytes`, `Unaligned`: Per the reference [1], `str`
+    ///   has the same layout as `[u8]`, and `[u8]` is `FromZeroes`, `AsBytes`,
+    ///   and `Unaligned`.
+    ///
+    /// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!`
+    /// uses `align_of`, which only works for `Sized` types.
+    ///
+    /// TODO(#429): Add quotes from documentation.
+    ///
+    /// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout
+    unsafe_impl!(str: FromZeroes, AsBytes, Unaligned);
+    /// SAFETY:
+    /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
+    ///   closure:
+    ///   - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object
+    ///     of the same size as that referred to by `t`. This is true because
+    ///     `str` and `[u8]` have the same representation. [1]
+    ///   - Since the closure takes a `&[u8]` argument, given a `Ptr<'a, str>`
+    ///     which satisfies the preconditions of
+    ///     `TryFromBytes::<str>::is_bit_valid`, it must be guaranteed that the
+    ///     memory referenced by that `Ptr` always contains a valid `[u8]`.
+    ///     Since `str`'s bytes are always initialized [1], `is_bit_valid`'s
+    ///     precondition requires that the same is true of its argument. Since
+    ///     `[u8]`'s only bit validity invariant is that its bytes must be
+    ///     initialized, this memory is guaranteed to contain a valid `[u8]`.
+    ///   - The alignment of `str` is equal to the alignment of `[u8]`. [1]
+    ///   - The impl must only return `true` for its argument if the original
+    ///     `Ptr<str>` refers to a valid `str`. `str::from_utf8` guarantees that
+    ///     it returns `Err` if its input is not a valid `str`. [2]
+    ///
+    /// [1] Per https://doc.rust-lang.org/reference/types/textual.html:
+    ///
+    ///   A value of type `str` is represented the same was as `[u8]`.
+    ///
+    /// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors:
+    ///
+    ///   Returns `Err` if the slice is not UTF-8.
+    unsafe_impl!(str: TryFromBytes; |candidate: &[u8]| core::str::from_utf8(candidate).is_ok());
+}
+
+safety_comment! {
+    // `NonZeroXxx` is `AsBytes`, but not `FromZeroes` or `FromBytes`.
+    //
+    /// SAFETY:
+    /// - `AsBytes`: `NonZeroXxx` has the same layout as its associated
+    ///    primitive. Since it is the same size, this guarantees it has no
+    ///    padding - integers have no padding, and there's no room for padding
+    ///    if it can represent all of the same values except 0.
+    /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
+    ///   `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
+    ///   This is worded in a way that makes it unclear whether it's meant as a
+    ///   guarantee, but given the purpose of those types, it's virtually
+    ///   unthinkable that that would ever change. `Option` cannot be smaller
+    ///   than its contained type, which implies that, and `NonZeroX8` are of
+    ///   size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot
+    ///   be 0 bytes, which means that they must be 1 byte. The only valid
+    ///   alignment for a 1-byte type is 1.
+    ///
+    /// TODO(#429): Add quotes from documentation.
+    ///
+    /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
+    /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
+    /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
+    /// that layout is the same as primitive layout.
+    unsafe_impl!(NonZeroU8: AsBytes, Unaligned);
+    unsafe_impl!(NonZeroI8: AsBytes, Unaligned);
+    assert_unaligned!(NonZeroU8, NonZeroI8);
+    unsafe_impl!(NonZeroU16: AsBytes);
+    unsafe_impl!(NonZeroI16: AsBytes);
+    unsafe_impl!(NonZeroU32: AsBytes);
+    unsafe_impl!(NonZeroI32: AsBytes);
+    unsafe_impl!(NonZeroU64: AsBytes);
+    unsafe_impl!(NonZeroI64: AsBytes);
+    unsafe_impl!(NonZeroU128: AsBytes);
+    unsafe_impl!(NonZeroI128: AsBytes);
+    unsafe_impl!(NonZeroUsize: AsBytes);
+    unsafe_impl!(NonZeroIsize: AsBytes);
+    /// SAFETY:
+    /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
+    ///   closure:
+    ///   - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an
+    ///     object of the same size as that referred to by `t`. This is true
+    ///     because `NonZeroXxx` and `xxx` have the same size. [1]
+    ///   - Since the closure takes a `&xxx` argument, given a `Ptr<'a,
+    ///     NonZeroXxx>` which satisfies the preconditions of
+    ///     `TryFromBytes::<NonZeroXxx>::is_bit_valid`, it must be guaranteed
+    ///     that the memory referenced by that `Ptr` always contains a valid
+    ///     `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1],
+    ///     `is_bit_valid`'s precondition requires that the same is true of its
+    ///     argument. Since `xxx`'s only bit validity invariant is that its
+    ///     bytes must be initialized, this memory is guaranteed to contain a
+    ///     valid `xxx`.
+    ///   - The alignment of `NonZeroXxx` is equal to the alignment of `xxx`.
+    ///     [1]
+    ///   - The impl must only return `true` for its argument if the original
+    ///     `Ptr<NonZeroXxx>` refers to a valid `NonZeroXxx`. The only `xxx`
+    ///     which is not also a valid `NonZeroXxx` is 0. [1]
+    ///
+    /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html:
+    ///
+    ///   `NonZeroU16` is guaranteed to have the same layout and bit validity as
+    ///   `u16` with the exception that `0` is not a valid instance.
+    unsafe_impl!(NonZeroU8: TryFromBytes; |n: &u8| *n != 0);
+    unsafe_impl!(NonZeroI8: TryFromBytes; |n: &i8| *n != 0);
+    unsafe_impl!(NonZeroU16: TryFromBytes; |n: &u16| *n != 0);
+    unsafe_impl!(NonZeroI16: TryFromBytes; |n: &i16| *n != 0);
+    unsafe_impl!(NonZeroU32: TryFromBytes; |n: &u32| *n != 0);
+    unsafe_impl!(NonZeroI32: TryFromBytes; |n: &i32| *n != 0);
+    unsafe_impl!(NonZeroU64: TryFromBytes; |n: &u64| *n != 0);
+    unsafe_impl!(NonZeroI64: TryFromBytes; |n: &i64| *n != 0);
+    unsafe_impl!(NonZeroU128: TryFromBytes; |n: &u128| *n != 0);
+    unsafe_impl!(NonZeroI128: TryFromBytes; |n: &i128| *n != 0);
+    unsafe_impl!(NonZeroUsize: TryFromBytes; |n: &usize| *n != 0);
+    unsafe_impl!(NonZeroIsize: TryFromBytes; |n: &isize| *n != 0);
+}
+safety_comment! {
+    /// SAFETY:
+    /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`,
+    ///   `AsBytes`: The Rust compiler reuses `0` value to represent `None`, so
+    ///   `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see
+    ///   `NonZeroXxx` documentation.
+    /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
+    ///   `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
+    ///   This is worded in a way that makes it unclear whether it's meant as a
+    ///   guarantee, but given the purpose of those types, it's virtually
+    ///   unthinkable that that would ever change. The only valid alignment for
+    ///   a 1-byte type is 1.
+    ///
+    /// TODO(#429): Add quotes from documentation.
+    ///
+    /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
+    /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
+    ///
+    /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
+    /// for layout guarantees.
+    unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+    unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+    assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
+    unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+    unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeroes, FromBytes, AsBytes);
+}
+
+safety_comment! {
+    /// SAFETY:
+    /// The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]
+    /// None of them contain `UnsafeCell`s, and so they all soundly implement
+    /// `FromZeroes`.
+    ///
+    /// [1] Per
+    /// https://doc.rust-lang.org/nightly/core/option/index.html#representation:
+    ///
+    ///   Rust guarantees to optimize the following types `T` such that
+    ///   [`Option<T>`] has the same size and alignment as `T`. In some of these
+    ///   cases, Rust further guarantees that `transmute::<_, Option<T>>([0u8;
+    ///   size_of::<T>()])` is sound and produces `Option::<T>::None`. These
+    ///   cases are identified by the second column:
+    ///
+    ///   | `T`                   | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
+    ///   |-----------------------|-----------------------------------------------------------|
+    ///   | [`Box<U>`]            | when `U: Sized`                                           |
+    ///   | `&U`                  | when `U: Sized`                                           |
+    ///   | `&mut U`              | when `U: Sized`                                           |
+    ///   | [`ptr::NonNull<U>`]   | when `U: Sized`                                           |
+    ///   | `fn`, `extern "C" fn` | always                                                    |
+    ///
+    /// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite
+    /// the Stable docs once they're available.
+    #[cfg(feature = "alloc")]
+    unsafe_impl!(
+        #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+        T => FromZeroes for Option<Box<T>>
+    );
+    unsafe_impl!(T => FromZeroes for Option<&'_ T>);
+    unsafe_impl!(T => FromZeroes for Option<&'_ mut T>);
+    unsafe_impl!(T => FromZeroes for Option<NonNull<T>>);
+    unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_fn!(...));
+    unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_extern_c_fn!(...));
+}
+
+safety_comment! {
+    /// SAFETY:
+    /// Per reference [1]:
+    /// "For all T, the following are guaranteed:
+    /// size_of::<PhantomData<T>>() == 0
+    /// align_of::<PhantomData<T>>() == 1".
+    /// This gives:
+    /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There
+    ///   is only one possible sequence of 0 bytes, and `PhantomData` is
+    ///   inhabited.
+    /// - `AsBytes`: Since `PhantomData` has size 0, it contains no padding
+    ///   bytes.
+    /// - `Unaligned`: Per the preceding reference, `PhantomData` has alignment
+    ///   1.
+    ///
+    /// [1] https://doc.rust-lang.org/std/marker/struct.PhantomData.html#layout-1
+    unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => FromZeroes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => AsBytes for PhantomData<T>);
+    unsafe_impl!(T: ?Sized => Unaligned for PhantomData<T>);
+    assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
+}
+safety_comment! {
+    /// SAFETY:
+    /// `Wrapping<T>` is guaranteed by its docs [1] to have the same layout and
+    /// bit validity as `T`. Also, `Wrapping<T>` is `#[repr(transparent)]`, and
+    /// has a single field, which is `pub`. Per the reference [2], this means
+    /// that the `#[repr(transparent)]` attribute is "considered part of the
+    /// public ABI".
+    ///
+    /// - `TryFromBytes`: The safety requirements for `unsafe_impl!` with an
+    ///   `is_bit_valid` closure:
+    ///   - Given `t: *mut Wrapping<T>` and `let r = *mut T`, `r` refers to an
+    ///     object of the same size as that referred to by `t`. This is true
+    ///     because `Wrapping<T>` and `T` have the same layout
+    ///   - The alignment of `Wrapping<T>` is equal to the alignment of `T`.
+    ///   - The impl must only return `true` for its argument if the original
+    ///     `Ptr<Wrapping<T>>` refers to a valid `Wrapping<T>`. Since
+    ///     `Wrapping<T>` has the same bit validity as `T`, and since our impl
+    ///     just calls `T::is_bit_valid`, our impl returns `true` exactly when
+    ///     its argument contains a valid `Wrapping<T>`.
+    /// - `FromBytes`: Since `Wrapping<T>` has the same bit validity as `T`, if
+    ///   `T: FromBytes`, then all initialized byte sequences are valid
+    ///   instances of `Wrapping<T>`. Similarly, if `T: FromBytes`, then
+    ///   `Wrapping<T>` doesn't contain any `UnsafeCell`s. Thus, `impl FromBytes
+    ///   for Wrapping<T> where T: FromBytes` is a sound impl.
+    /// - `AsBytes`: Since `Wrapping<T>` has the same bit validity as `T`, if
+    ///   `T: AsBytes`, then all valid instances of `Wrapping<T>` have all of
+    ///   their bytes initialized. Similarly, if `T: AsBytes`, then
+    ///   `Wrapping<T>` doesn't contain any `UnsafeCell`s. Thus, `impl AsBytes
+    ///   for Wrapping<T> where T: AsBytes` is a valid impl.
+    /// - `Unaligned`: Since `Wrapping<T>` has the same layout as `T`,
+    ///   `Wrapping<T>` has alignment 1 exactly when `T` does.
+    ///
+    /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html:
+    ///
+    ///   `NonZeroU16` is guaranteed to have the same layout and bit validity as
+    ///   `u16` with the exception that `0` is not a valid instance.
+    ///
+    /// TODO(#429): Add quotes from documentation.
+    ///
+    /// [1] TODO(https://doc.rust-lang.org/nightly/core/num/struct.Wrapping.html#layout-1):
+    /// Reference this documentation once it's available on stable.
+    ///
+    /// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
+    unsafe_impl!(T: TryFromBytes => TryFromBytes for Wrapping<T>; |candidate: Ptr<T>| {
+        // SAFETY:
+        // - Since `T` and `Wrapping<T>` have the same layout and bit validity
+        //   and contain the same fields, `T` contains `UnsafeCell`s exactly
+        //   where `Wrapping<T>` does. Thus, all memory and `UnsafeCell`
+        //   preconditions of `T::is_bit_valid` hold exactly when the same
+        //   preconditions for `Wrapping<T>::is_bit_valid` hold.
+        // - By the same token, since `candidate` is guaranteed to have its
+        //   bytes initialized where there are always initialized bytes in
+        //   `Wrapping<T>`, the same is true for `T`.
+        unsafe { T::is_bit_valid(candidate) }
+    });
+    unsafe_impl!(T: FromZeroes => FromZeroes for Wrapping<T>);
+    unsafe_impl!(T: FromBytes => FromBytes for Wrapping<T>);
+    unsafe_impl!(T: AsBytes => AsBytes for Wrapping<T>);
+    unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>);
+    assert_unaligned!(Wrapping<()>, Wrapping<u8>);
+}
+safety_comment! {
+    // `MaybeUninit<T>` is `FromZeroes` and `FromBytes`, but never `AsBytes`
+    // since it may contain uninitialized bytes.
+    //
+    /// SAFETY:
+    /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`:
+    ///   `MaybeUninit<T>` has no restrictions on its contents. Unfortunately,
+    ///   in addition to bit validity, `TryFromBytes`, `FromZeroes` and
+    ///   `FromBytes` also require that implementers contain no `UnsafeCell`s.
+    ///   Thus, we require `T: Trait` in order to ensure that `T` - and thus
+    ///   `MaybeUninit<T>` - contains to `UnsafeCell`s. Thus, requiring that `T`
+    ///   implement each of these traits is sufficient.
+    /// - `Unaligned`: "MaybeUninit<T> is guaranteed to have the same size,
+    ///    alignment, and ABI as T" [1]
+    ///
+    /// [1] https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#layout-1
+    ///
+    /// TODO(https://github.com/google/zerocopy/issues/251): If we split
+    /// `FromBytes` and `RefFromBytes`, or if we introduce a separate
+    /// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
+    /// and `FromBytes`.
+    unsafe_impl!(T: TryFromBytes => TryFromBytes for MaybeUninit<T>);
+    unsafe_impl!(T: FromZeroes => FromZeroes for MaybeUninit<T>);
+    unsafe_impl!(T: FromBytes => FromBytes for MaybeUninit<T>);
+    unsafe_impl!(T: Unaligned => Unaligned for MaybeUninit<T>);
+    assert_unaligned!(MaybeUninit<()>, MaybeUninit<u8>);
+}
+safety_comment! {
+    /// SAFETY:
+    /// `ManuallyDrop` has the same layout and bit validity as `T` [1], and
+    /// accessing the inner value is safe (meaning that it's unsound to leave
+    /// the inner value uninitialized while exposing the `ManuallyDrop` to safe
+    /// code).
+    /// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any
+    ///   valid `T` is a valid `ManuallyDrop<T>`. If `T: FromZeroes`, a sequence
+    ///   of zero bytes is a valid `T`, and thus a valid `ManuallyDrop<T>`. If
+    ///   `T: FromBytes`, any sequence of bytes is a valid `T`, and thus a valid
+    ///   `ManuallyDrop<T>`.
+    /// - `AsBytes`: Since it has the same layout as `T`, and since it's unsound
+    ///   to let safe code access a `ManuallyDrop` whose inner value is
+    ///   uninitialized, safe code can only ever access a `ManuallyDrop` whose
+    ///   contents are a valid `T`. Since `T: AsBytes`, this means that safe
+    ///   code can only ever access a `ManuallyDrop` with all initialized bytes.
+    /// - `Unaligned`: `ManuallyDrop` has the same layout (and thus alignment)
+    ///   as `T`, and `T: Unaligned` guarantees that that alignment is 1.
+    ///
+    ///   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
+    ///   validity as `T`
+    ///
+    /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
+    ///
+    /// TODO(#429):
+    /// - Add quotes from docs.
+    /// - Once [1] (added in
+    /// https://github.com/rust-lang/rust/pull/115522) is available on stable,
+    /// quote the stable docs instead of the nightly docs.
+    unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop<T>);
+    unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
+    unsafe_impl!(T: ?Sized + AsBytes => AsBytes for ManuallyDrop<T>);
+    unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
+    assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
+}
+safety_comment! {
+    /// SAFETY:
+    /// Per the reference [1]:
+    ///
+    ///   An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
+    ///   alignment of `T`. Arrays are laid out so that the zero-based `nth`
+    ///   element of the array is offset from the start of the array by `n *
+    ///   size_of::<T>()` bytes.
+    ///
+    ///   ...
+    ///
+    ///   Slices have the same layout as the section of the array they slice.
+    ///
+    /// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s
+    /// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T;
+    /// N]` are `TryFromBytes`, `FromZeroes`, `FromBytes`, and `AsBytes` if `T`
+    /// is (respectively). Furthermore, since an array/slice has "the same
+    /// alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is.
+    ///
+    /// Note that we don't `assert_unaligned!` for slice types because
+    /// `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
+    ///
+    /// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
+    unsafe_impl!(const N: usize, T: FromZeroes => FromZeroes for [T; N]);
+    unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
+    unsafe_impl!(const N: usize, T: AsBytes => AsBytes for [T; N]);
+    unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
+    assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
+    unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c: Ptr<[T]>| {
+        // SAFETY: Assuming the preconditions of `is_bit_valid` are satisfied,
+        // so too will the postcondition: that, if `is_bit_valid(candidate)`
+        // returns true, `*candidate` contains a valid `Self`. Per the reference
+        // [1]:
+        //
+        //   An array of `[T; N]` has a size of `size_of::<T>() * N` and the
+        //   same alignment of `T`. Arrays are laid out so that the zero-based
+        //   `nth` element of the array is offset from the start of the array by
+        //   `n * size_of::<T>()` bytes.
+        //
+        //   ...
+        //
+        //   Slices have the same layout as the section of the array they slice.
+        //
+        // In other words, the layout of a `[T] is a sequence of `T`s laid out
+        // back-to-back with no bytes in between. If all elements in `candidate`
+        // are `is_bit_valid`, so too is `candidate`.
+        //
+        // Note that any of the below calls may panic, but it would still be
+        // sound even if it did. `is_bit_valid` does not promise that it will
+        // not panic (in fact, it explicitly warns that it's a possibility), and
+        // we have not violated any safety invariants that we must fix before
+        // returning.
+        c.iter().all(|elem|
+            // SAFETY: We uphold the safety contract of `is_bit_valid(elem)`, by
+            // precondition on the surrounding call to `is_bit_valid`. The
+            // memory referenced by `elem` is contained entirely within `c`, and
+            // satisfies the preconditions satisfied by `c`. By axiom, we assume
+            // that `Iterator:all` does not invalidate these preconditions
+            // (e.g., by writing to `elem`.) Since `elem` is derived from `c`,
+            // it is only possible for uninitialized bytes to occur in `elem` at
+            // the same bytes they occur within `c`.
+            unsafe { <T as TryFromBytes>::is_bit_valid(elem) }
+        )
+    });
+    unsafe_impl!(T: FromZeroes => FromZeroes for [T]);
+    unsafe_impl!(T: FromBytes => FromBytes for [T]);
+    unsafe_impl!(T: AsBytes => AsBytes for [T]);
+    unsafe_impl!(T: Unaligned => Unaligned for [T]);
+}
+safety_comment! {
+    /// SAFETY:
+    /// - `FromZeroes`: For thin pointers (note that `T: Sized`), the zero
+    ///   pointer is considered "null". [1] No operations which require
+    ///   provenance are legal on null pointers, so this is not a footgun.
+    ///
+    /// NOTE(#170): Implementing `FromBytes` and `AsBytes` for raw pointers
+    /// would be sound, but carries provenance footguns. We want to support
+    /// `FromBytes` and `AsBytes` for raw pointers eventually, but we are
+    /// holding off until we can figure out how to address those footguns.
+    ///
+    /// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the
+    /// documentation once this PR lands.
+    unsafe_impl!(T => FromZeroes for *const T);
+    unsafe_impl!(T => FromZeroes for *mut T);
+}
+
+// SIMD support
+//
+// Per the Unsafe Code Guidelines Reference [1]:
+//
+//   Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs
+//   containing `N` elements of type `T` where `N` is a power-of-two and the
+//   size and alignment requirements of `T` are equal:
+//
+//   ```rust
+//   #[repr(simd)]
+//   struct Vector<T, N>(T_0, ..., T_(N - 1));
+//   ```
+//
+//   ...
+//
+//   The size of `Vector` is `N * size_of::<T>()` and its alignment is an
+//   implementation-defined function of `T` and `N` greater than or equal to
+//   `align_of::<T>()`.
+//
+//   ...
+//
+//   Vector elements are laid out in source field order, enabling random access
+//   to vector elements by reinterpreting the vector as an array:
+//
+//   ```rust
+//   union U {
+//      vec: Vector<T, N>,
+//      arr: [T; N]
+//   }
+//
+//   assert_eq!(size_of::<Vector<T, N>>(), size_of::<[T; N]>());
+//   assert!(align_of::<Vector<T, N>>() >= align_of::<[T; N]>());
+//
+//   unsafe {
+//     let u = U { vec: Vector<T, N>(t_0, ..., t_(N - 1)) };
+//
+//     assert_eq!(u.vec.0, u.arr[0]);
+//     // ...
+//     assert_eq!(u.vec.(N - 1), u.arr[N - 1]);
+//   }
+//   ```
+//
+// Given this background, we can observe that:
+// - The size and bit pattern requirements of a SIMD type are equivalent to the
+//   equivalent array type. Thus, for any SIMD type whose primitive `T` is
+//   `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes`, that SIMD type is
+//   also `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` respectively.
+// - Since no upper bound is placed on the alignment, no SIMD type can be
+//   guaranteed to be `Unaligned`.
+//
+// Also per [1]:
+//
+//   This chapter represents the consensus from issue #38. The statements in
+//   here are not (yet) "guaranteed" not to change until an RFC ratifies them.
+//
+// See issue #38 [2]. While this behavior is not technically guaranteed, the
+// likelihood that the behavior will change such that SIMD types are no longer
+// `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` is next to zero, as
+// that would defeat the entire purpose of SIMD types. Nonetheless, we put this
+// behavior behind the `simd` Cargo feature, which requires consumers to opt
+// into this stability hazard.
+//
+// [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
+// [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38
+#[cfg(feature = "simd")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))]
+mod simd {
+    /// Defines a module which implements `TryFromBytes`, `FromZeroes`,
+    /// `FromBytes`, and `AsBytes` for a set of types from a module in
+    /// `core::arch`.
+    ///
+    /// `$arch` is both the name of the defined module and the name of the
+    /// module in `core::arch`, and `$typ` is the list of items from that module
+    /// to implement `FromZeroes`, `FromBytes`, and `AsBytes` for.
+    #[allow(unused_macros)] // `allow(unused_macros)` is needed because some
+                            // target/feature combinations don't emit any impls
+                            // and thus don't use this macro.
+    macro_rules! simd_arch_mod {
+        (#[cfg $cfg:tt] $arch:ident, $mod:ident, $($typ:ident),*) => {
+            #[cfg $cfg]
+            #[cfg_attr(doc_cfg, doc(cfg $cfg))]
+            mod $mod {
+                use core::arch::$arch::{$($typ),*};
+
+                use crate::*;
+                impl_known_layout!($($typ),*);
+                safety_comment! {
+                    /// SAFETY:
+                    /// See comment on module definition for justification.
+                    $( unsafe_impl!($typ: TryFromBytes, FromZeroes, FromBytes, AsBytes); )*
+                }
+            }
+        };
+    }
+
+    #[rustfmt::skip]
+    const _: () = {
+        simd_arch_mod!(
+            #[cfg(target_arch = "x86")]
+            x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i
+        );
+        simd_arch_mod!(
+            #[cfg(all(feature = "simd-nightly", target_arch = "x86"))]
+            x86, x86_nightly, __m512bh, __m512, __m512d, __m512i
+        );
+        simd_arch_mod!(
+            #[cfg(target_arch = "x86_64")]
+            x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i
+        );
+        simd_arch_mod!(
+            #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))]
+            x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i
+        );
+        simd_arch_mod!(
+            #[cfg(target_arch = "wasm32")]
+            wasm32, wasm32, v128
+        );
+        simd_arch_mod!(
+            #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
+            powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
+        );
+        simd_arch_mod!(
+            #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
+            powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
+        );
+        simd_arch_mod!(
+            #[cfg(target_arch = "aarch64")]
+            aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
+            int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
+            int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
+            poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
+            poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
+            uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t,
+            uint64x1_t, uint64x2_t
+        );
+        simd_arch_mod!(
+            #[cfg(all(feature = "simd-nightly", target_arch = "arm"))]
+            arm, arm, int8x4_t, uint8x4_t
+        );
+    };
+}
+
+/// Safely transmutes a value of one type to a value of another type of the same
+/// size.
+///
+/// The expression `$e` must have a concrete type, `T`, which implements
+/// `AsBytes`. The `transmute!` expression must also have a concrete type, `U`
+/// (`U` is inferred from the calling context), and `U` must implement
+/// `FromBytes`.
+///
+/// Note that the `T` produced by the expression `$e` will *not* be dropped.
+/// Semantically, its bits will be copied into a new value of type `U`, the
+/// original `T` will be forgotten, and the value of type `U` will be returned.
+///
+/// # Examples
+///
+/// ```
+/// # use zerocopy::transmute;
+/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
+///
+/// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional);
+///
+/// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]);
+/// ```
+#[macro_export]
+macro_rules! transmute {
+    ($e:expr) => {{
+        // NOTE: This must be a macro (rather than a function with trait bounds)
+        // because there's no way, in a generic context, to enforce that two
+        // types have the same size. `core::mem::transmute` uses compiler magic
+        // to enforce this so long as the types are concrete.
+
+        let e = $e;
+        if false {
+            // This branch, though never taken, ensures that the type of `e` is
+            // `AsBytes` and that the type of this macro invocation expression
+            // is `FromBytes`.
+
+            struct AssertIsAsBytes<T: $crate::AsBytes>(T);
+            let _ = AssertIsAsBytes(e);
+
+            struct AssertIsFromBytes<U: $crate::FromBytes>(U);
+            #[allow(unused, unreachable_code)]
+            let u = AssertIsFromBytes(loop {});
+            u.0
+        } else {
+            // SAFETY: `core::mem::transmute` ensures that the type of `e` and
+            // the type of this macro invocation expression have the same size.
+            // We know this transmute is safe thanks to the `AsBytes` and
+            // `FromBytes` bounds enforced by the `false` branch.
+            //
+            // We use this reexport of `core::mem::transmute` because we know it
+            // will always be available for crates which are using the 2015
+            // edition of Rust. By contrast, if we were to use
+            // `std::mem::transmute`, this macro would not work for such crates
+            // in `no_std` contexts, and if we were to use
+            // `core::mem::transmute`, this macro would not work in `std`
+            // contexts in which `core` was not manually imported. This is not a
+            // problem for 2018 edition crates.
+            unsafe {
+                // Clippy: It's okay to transmute a type to itself.
+                #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)]
+                $crate::macro_util::core_reexport::mem::transmute(e)
+            }
+        }
+    }}
+}
+
+/// Safely transmutes a mutable or immutable reference of one type to an
+/// immutable reference of another type of the same size.
+///
+/// The expression `$e` must have a concrete type, `&T` or `&mut T`, where `T:
+/// Sized + AsBytes`. The `transmute_ref!` expression must also have a concrete
+/// type, `&U` (`U` is inferred from the calling context), where `U: Sized +
+/// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
+///
+/// The lifetime of the input type, `&T` or `&mut T`, must be the same as or
+/// outlive the lifetime of the output type, `&U`.
+///
+/// # Examples
+///
+/// ```
+/// # use zerocopy::transmute_ref;
+/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
+///
+/// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional);
+///
+/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
+/// ```
+///
+/// # Alignment increase error message
+///
+/// Because of limitations on macros, the error message generated when
+/// `transmute_ref!` is used to transmute from a type of lower alignment to a
+/// type of higher alignment is somewhat confusing. For example, the following
+/// code:
+///
+/// ```compile_fail
+/// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
+/// ```
+///
+/// ...generates the following error:
+///
+/// ```text
+/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+///  --> src/lib.rs:1524:34
+///   |
+/// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
+///   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+///   |
+///   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+///   = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
+///   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+/// ```
+///
+/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
+/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
+/// align_of::<U>()`.
+#[macro_export]
+macro_rules! transmute_ref {
+    ($e:expr) => {{
+        // NOTE: This must be a macro (rather than a function with trait bounds)
+        // because there's no way, in a generic context, to enforce that two
+        // types have the same size or alignment.
+
+        // Ensure that the source type is a reference or a mutable reference
+        // (note that mutable references are implicitly reborrowed here).
+        let e: &_ = $e;
+
+        #[allow(unused, clippy::diverging_sub_expression)]
+        if false {
+            // This branch, though never taken, ensures that the type of `e` is
+            // `&T` where `T: 't + Sized + AsBytes`, that the type of this macro
+            // expression is `&U` where `U: 'u + Sized + FromBytes`, and that
+            // `'t` outlives `'u`.
+
+            struct AssertIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);
+            let _ = AssertIsAsBytes(e);
+
+            struct AssertIsFromBytes<'a, U: ::core::marker::Sized + $crate::FromBytes>(&'a U);
+            #[allow(unused, unreachable_code)]
+            let u = AssertIsFromBytes(loop {});
+            u.0
+        } else if false {
+            // This branch, though never taken, ensures that `size_of::<T>() ==
+            // size_of::<U>()` and that that `align_of::<T>() >=
+            // align_of::<U>()`.
+
+            // `t` is inferred to have type `T` because it's assigned to `e` (of
+            // type `&T`) as `&t`.
+            let mut t = unreachable!();
+            e = &t;
+
+            // `u` is inferred to have type `U` because it's used as `&u` as the
+            // value returned from this branch.
+            let u;
+
+            $crate::assert_size_eq!(t, u);
+            $crate::assert_align_gt_eq!(t, u);
+
+            &u
+        } else {
+            // SAFETY: For source type `Src` and destination type `Dst`:
+            // - We know that `Src: AsBytes` and `Dst: FromBytes` thanks to the
+            //   uses of `AssertIsAsBytes` and `AssertIsFromBytes` above.
+            // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
+            //   the use of `assert_size_eq!` above.
+            // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
+            //   the use of `assert_align_gt_eq!` above.
+            unsafe { $crate::macro_util::transmute_ref(e) }
+        }
+    }}
+}
+
+/// Safely transmutes a mutable reference of one type to an mutable reference of
+/// another type of the same size.
+///
+/// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized +
+/// AsBytes`. The `transmute_mut!` expression must also have a concrete type,
+/// `&mut U` (`U` is inferred from the calling context), where `U: Sized +
+/// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
+///
+/// The lifetime of the input type, `&mut T`, must be the same as or outlive the
+/// lifetime of the output type, `&mut U`.
+///
+/// # Examples
+///
+/// ```
+/// # use zerocopy::transmute_mut;
+/// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
+///
+/// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional);
+///
+/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
+///
+/// two_dimensional.reverse();
+///
+/// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]);
+/// ```
+///
+/// # Alignment increase error message
+///
+/// Because of limitations on macros, the error message generated when
+/// `transmute_mut!` is used to transmute from a type of lower alignment to a
+/// type of higher alignment is somewhat confusing. For example, the following
+/// code:
+///
+/// ```compile_fail
+/// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
+/// ```
+///
+/// ...generates the following error:
+///
+/// ```text
+/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+///  --> src/lib.rs:1524:34
+///   |
+/// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
+///   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+///   |
+///   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+///   = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
+///   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+/// ```
+///
+/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
+/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
+/// align_of::<U>()`.
+#[macro_export]
+macro_rules! transmute_mut {
+    ($e:expr) => {{
+        // NOTE: This must be a macro (rather than a function with trait bounds)
+        // because there's no way, in a generic context, to enforce that two
+        // types have the same size or alignment.
+
+        // Ensure that the source type is a mutable reference.
+        let e: &mut _ = $e;
+
+        #[allow(unused, clippy::diverging_sub_expression)]
+        if false {
+            // This branch, though never taken, ensures that the type of `e` is
+            // `&mut T` where `T: 't + Sized + FromBytes + AsBytes`, that the
+            // type of this macro expression is `&mut U` where `U: 'u + Sized +
+            // FromBytes + AsBytes`.
+
+            // We use immutable references here rather than mutable so that, if
+            // this macro is used in a const context (in which, as of this
+            // writing, mutable references are banned), the error message
+            // appears to originate in the user's code rather than in the
+            // internals of this macro.
+            struct AssertSrcIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T);
+            struct AssertSrcIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);
+            struct AssertDstIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T);
+            struct AssertDstIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T);
+
+            if true {
+                let _ = AssertSrcIsFromBytes(&*e);
+            } else {
+                let _ = AssertSrcIsAsBytes(&*e);
+            }
+
+            if true {
+                #[allow(unused, unreachable_code)]
+                let u = AssertDstIsFromBytes(loop {});
+                &mut *u.0
+            } else {
+                #[allow(unused, unreachable_code)]
+                let u = AssertDstIsAsBytes(loop {});
+                &mut *u.0
+            }
+        } else if false {
+            // This branch, though never taken, ensures that `size_of::<T>() ==
+            // size_of::<U>()` and that that `align_of::<T>() >=
+            // align_of::<U>()`.
+
+            // `t` is inferred to have type `T` because it's assigned to `e` (of
+            // type `&mut T`) as `&mut t`.
+            let mut t = unreachable!();
+            e = &mut t;
+
+            // `u` is inferred to have type `U` because it's used as `&mut u` as
+            // the value returned from this branch.
+            let u;
+
+            $crate::assert_size_eq!(t, u);
+            $crate::assert_align_gt_eq!(t, u);
+
+            &mut u
+        } else {
+            // SAFETY: For source type `Src` and destination type `Dst`:
+            // - We know that `Src: FromBytes + AsBytes` and `Dst: FromBytes +
+            //   AsBytes` thanks to the uses of `AssertSrcIsFromBytes`,
+            //   `AssertSrcIsAsBytes`, `AssertDstIsFromBytes`, and
+            //   `AssertDstIsAsBytes` above.
+            // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
+            //   the use of `assert_size_eq!` above.
+            // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
+            //   the use of `assert_align_gt_eq!` above.
+            unsafe { $crate::macro_util::transmute_mut(e) }
+        }
+    }}
+}
+
+/// Includes a file and safely transmutes it to a value of an arbitrary type.
+///
+/// The file will be included as a byte array, `[u8; N]`, which will be
+/// transmuted to another type, `T`. `T` is inferred from the calling context,
+/// and must implement [`FromBytes`].
+///
+/// The file is located relative to the current file (similarly to how modules
+/// are found). The provided path is interpreted in a platform-specific way at
+/// compile time. So, for instance, an invocation with a Windows path containing
+/// backslashes `\` would not compile correctly on Unix.
+///
+/// `include_value!` is ignorant of byte order. For byte order-aware types, see
+/// the [`byteorder`] module.
+///
+/// # Examples
+///
+/// Assume there are two files in the same directory with the following
+/// contents:
+///
+/// File `data` (no trailing newline):
+///
+/// ```text
+/// abcd
+/// ```
+///
+/// File `main.rs`:
+///
+/// ```rust
+/// use zerocopy::include_value;
+/// # macro_rules! include_value {
+/// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) };
+/// # }
+///
+/// fn main() {
+///     let as_u32: u32 = include_value!("data");
+///     assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
+///     let as_i32: i32 = include_value!("data");
+///     assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
+/// }
+/// ```
+#[doc(alias("include_bytes", "include_data", "include_type"))]
+#[macro_export]
+macro_rules! include_value {
+    ($file:expr $(,)?) => {
+        $crate::transmute!(*::core::include_bytes!($file))
+    };
+}
+
+/// A typed reference derived from a byte slice.
+///
+/// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.
+/// Unlike a native reference (`&T` or `&mut T`), `Ref<B, T>` has the same
+/// mutability as the byte slice it was constructed from (`B`).
+///
+/// # Examples
+///
+/// `Ref` can be used to treat a sequence of bytes as a structured type, and to
+/// read and write the fields of that type as if the byte slice reference were
+/// simply a reference to that type.
+///
+/// ```rust
+/// # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them
+/// use zerocopy::{AsBytes, ByteSlice, ByteSliceMut, FromBytes, FromZeroes, Ref, Unaligned};
+///
+/// #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+/// #[repr(C)]
+/// struct UdpHeader {
+///     src_port: [u8; 2],
+///     dst_port: [u8; 2],
+///     length: [u8; 2],
+///     checksum: [u8; 2],
+/// }
+///
+/// struct UdpPacket<B> {
+///     header: Ref<B, UdpHeader>,
+///     body: B,
+/// }
+///
+/// impl<B: ByteSlice> UdpPacket<B> {
+///     pub fn parse(bytes: B) -> Option<UdpPacket<B>> {
+///         let (header, body) = Ref::new_unaligned_from_prefix(bytes)?;
+///         Some(UdpPacket { header, body })
+///     }
+///
+///     pub fn get_src_port(&self) -> [u8; 2] {
+///         self.header.src_port
+///     }
+/// }
+///
+/// impl<B: ByteSliceMut> UdpPacket<B> {
+///     pub fn set_src_port(&mut self, src_port: [u8; 2]) {
+///         self.header.src_port = src_port;
+///     }
+/// }
+/// # }
+/// ```
+pub struct Ref<B, T: ?Sized>(B, PhantomData<T>);
+
+/// Deprecated: prefer [`Ref`] instead.
+#[deprecated(since = "0.7.0", note = "LayoutVerified has been renamed to Ref")]
+#[doc(hidden)]
+pub type LayoutVerified<B, T> = Ref<B, T>;
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSlice,
+{
+    /// Constructs a new `Ref`.
+    ///
+    /// `new` verifies that `bytes.len() == size_of::<T>()` and that `bytes` is
+    /// aligned to `align_of::<T>()`, and constructs a new `Ref`. If either of
+    /// these checks fail, it returns `None`.
+    #[inline]
+    pub fn new(bytes: B) -> Option<Ref<B, T>> {
+        if bytes.len() != mem::size_of::<T>() || !util::aligned_to::<_, T>(bytes.deref()) {
+            return None;
+        }
+        Some(Ref(bytes, PhantomData))
+    }
+
+    /// Constructs a new `Ref` from the prefix of a byte slice.
+    ///
+    /// `new_from_prefix` verifies that `bytes.len() >= size_of::<T>()` and that
+    /// `bytes` is aligned to `align_of::<T>()`. It consumes the first
+    /// `size_of::<T>()` bytes from `bytes` to construct a `Ref`, and returns
+    /// the remaining bytes to the caller. If either the length or alignment
+    /// checks fail, it returns `None`.
+    #[inline]
+    pub fn new_from_prefix(bytes: B) -> Option<(Ref<B, T>, B)> {
+        if bytes.len() < mem::size_of::<T>() || !util::aligned_to::<_, T>(bytes.deref()) {
+            return None;
+        }
+        let (bytes, suffix) = bytes.split_at(mem::size_of::<T>());
+        Some((Ref(bytes, PhantomData), suffix))
+    }
+
+    /// Constructs a new `Ref` from the suffix of a byte slice.
+    ///
+    /// `new_from_suffix` verifies that `bytes.len() >= size_of::<T>()` and that
+    /// the last `size_of::<T>()` bytes of `bytes` are aligned to
+    /// `align_of::<T>()`. It consumes the last `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the preceding bytes to the
+    /// caller. If either the length or alignment checks fail, it returns
+    /// `None`.
+    #[inline]
+    pub fn new_from_suffix(bytes: B) -> Option<(B, Ref<B, T>)> {
+        let bytes_len = bytes.len();
+        let split_at = bytes_len.checked_sub(mem::size_of::<T>())?;
+        let (prefix, bytes) = bytes.split_at(split_at);
+        if !util::aligned_to::<_, T>(bytes.deref()) {
+            return None;
+        }
+        Some((prefix, Ref(bytes, PhantomData)))
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSlice,
+{
+    /// Constructs a new `Ref` of a slice type.
+    ///
+    /// `new_slice` verifies that `bytes.len()` is a multiple of
+    /// `size_of::<T>()` and that `bytes` is aligned to `align_of::<T>()`, and
+    /// constructs a new `Ref`. If either of these checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice` panics if `T` is a zero-sized type.
+    #[inline]
+    pub fn new_slice(bytes: B) -> Option<Ref<B, [T]>> {
+        let remainder = bytes
+            .len()
+            .checked_rem(mem::size_of::<T>())
+            .expect("Ref::new_slice called on a zero-sized type");
+        if remainder != 0 || !util::aligned_to::<_, T>(bytes.deref()) {
+            return None;
+        }
+        Some(Ref(bytes, PhantomData))
+    }
+
+    /// Constructs a new `Ref` of a slice type from the prefix of a byte slice.
+    ///
+    /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// first `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
+    /// and returns the remaining bytes to the caller. It also ensures that
+    /// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
+    /// length, alignment, or overflow checks fail, it returns `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_from_prefix` panics if `T` is a zero-sized type.
+    #[inline]
+    pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
+        let expected_len = match mem::size_of::<T>().checked_mul(count) {
+            Some(len) => len,
+            None => return None,
+        };
+        if bytes.len() < expected_len {
+            return None;
+        }
+        let (prefix, bytes) = bytes.split_at(expected_len);
+        Self::new_slice(prefix).map(move |l| (l, bytes))
+    }
+
+    /// Constructs a new `Ref` of a slice type from the suffix of a byte slice.
+    ///
+    /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// last `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
+    /// and returns the preceding bytes to the caller. It also ensures that
+    /// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
+    /// length, alignment, or overflow checks fail, it returns `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_from_suffix` panics if `T` is a zero-sized type.
+    #[inline]
+    pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
+        let expected_len = match mem::size_of::<T>().checked_mul(count) {
+            Some(len) => len,
+            None => return None,
+        };
+        let split_at = bytes.len().checked_sub(expected_len)?;
+        let (bytes, suffix) = bytes.split_at(split_at);
+        Self::new_slice(suffix).map(move |l| (bytes, l))
+    }
+}
+
+fn map_zeroed<B: ByteSliceMut, T: ?Sized>(opt: Option<Ref<B, T>>) -> Option<Ref<B, T>> {
+    match opt {
+        Some(mut r) => {
+            r.0.fill(0);
+            Some(r)
+        }
+        None => None,
+    }
+}
+
+fn map_prefix_tuple_zeroed<B: ByteSliceMut, T: ?Sized>(
+    opt: Option<(Ref<B, T>, B)>,
+) -> Option<(Ref<B, T>, B)> {
+    match opt {
+        Some((mut r, rest)) => {
+            r.0.fill(0);
+            Some((r, rest))
+        }
+        None => None,
+    }
+}
+
+fn map_suffix_tuple_zeroed<B: ByteSliceMut, T: ?Sized>(
+    opt: Option<(B, Ref<B, T>)>,
+) -> Option<(B, Ref<B, T>)> {
+    map_prefix_tuple_zeroed(opt.map(|(a, b)| (b, a))).map(|(a, b)| (b, a))
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSliceMut,
+{
+    /// Constructs a new `Ref` after zeroing the bytes.
+    ///
+    /// `new_zeroed` verifies that `bytes.len() == size_of::<T>()` and that
+    /// `bytes` is aligned to `align_of::<T>()`, and constructs a new `Ref`. If
+    /// either of these checks fail, it returns `None`.
+    ///
+    /// If the checks succeed, then `bytes` will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_zeroed(bytes: B) -> Option<Ref<B, T>> {
+        map_zeroed(Self::new(bytes))
+    }
+
+    /// Constructs a new `Ref` from the prefix of a byte slice, zeroing the
+    /// prefix.
+    ///
+    /// `new_from_prefix_zeroed` verifies that `bytes.len() >= size_of::<T>()`
+    /// and that `bytes` is aligned to `align_of::<T>()`. It consumes the first
+    /// `size_of::<T>()` bytes from `bytes` to construct a `Ref`, and returns
+    /// the remaining bytes to the caller. If either the length or alignment
+    /// checks fail, it returns `None`.
+    ///
+    /// If the checks succeed, then the prefix which is consumed will be
+    /// initialized to zero. This can be useful when re-using buffers to ensure
+    /// that sensitive data previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_from_prefix_zeroed(bytes: B) -> Option<(Ref<B, T>, B)> {
+        map_prefix_tuple_zeroed(Self::new_from_prefix(bytes))
+    }
+
+    /// Constructs a new `Ref` from the suffix of a byte slice, zeroing the
+    /// suffix.
+    ///
+    /// `new_from_suffix_zeroed` verifies that `bytes.len() >= size_of::<T>()`
+    /// and that the last `size_of::<T>()` bytes of `bytes` are aligned to
+    /// `align_of::<T>()`. It consumes the last `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the preceding bytes to the
+    /// caller. If either the length or alignment checks fail, it returns
+    /// `None`.
+    ///
+    /// If the checks succeed, then the suffix which is consumed will be
+    /// initialized to zero. This can be useful when re-using buffers to ensure
+    /// that sensitive data previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_from_suffix_zeroed(bytes: B) -> Option<(B, Ref<B, T>)> {
+        map_suffix_tuple_zeroed(Self::new_from_suffix(bytes))
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSliceMut,
+{
+    /// Constructs a new `Ref` of a slice type after zeroing the bytes.
+    ///
+    /// `new_slice_zeroed` verifies that `bytes.len()` is a multiple of
+    /// `size_of::<T>()` and that `bytes` is aligned to `align_of::<T>()`, and
+    /// constructs a new `Ref`. If either of these checks fail, it returns
+    /// `None`.
+    ///
+    /// If the checks succeed, then `bytes` will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_zeroed(bytes: B) -> Option<Ref<B, [T]>> {
+        map_zeroed(Self::new_slice(bytes))
+    }
+
+    /// Constructs a new `Ref` of a slice type from the prefix of a byte slice,
+    /// after zeroing the bytes.
+    ///
+    /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// first `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
+    /// and returns the remaining bytes to the caller. It also ensures that
+    /// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
+    /// length, alignment, or overflow checks fail, it returns `None`.
+    ///
+    /// If the checks succeed, then the suffix which is consumed will be
+    /// initialized to zero. This can be useful when re-using buffers to ensure
+    /// that sensitive data previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_from_prefix_zeroed` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_from_prefix_zeroed(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
+        map_prefix_tuple_zeroed(Self::new_slice_from_prefix(bytes, count))
+    }
+
+    /// Constructs a new `Ref` of a slice type from the prefix of a byte slice,
+    /// after zeroing the bytes.
+    ///
+    /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
+    /// last `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
+    /// and returns the preceding bytes to the caller. It also ensures that
+    /// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
+    /// length, alignment, or overflow checks fail, it returns `None`.
+    ///
+    /// If the checks succeed, then the consumed suffix will be initialized to
+    /// zero. This can be useful when re-using buffers to ensure that sensitive
+    /// data previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_from_suffix_zeroed` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_from_suffix_zeroed(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
+        map_suffix_tuple_zeroed(Self::new_slice_from_suffix(bytes, count))
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSlice,
+    T: Unaligned,
+{
+    /// Constructs a new `Ref` for a type with no alignment requirement.
+    ///
+    /// `new_unaligned` verifies that `bytes.len() == size_of::<T>()` and
+    /// constructs a new `Ref`. If the check fails, it returns `None`.
+    #[inline(always)]
+    pub fn new_unaligned(bytes: B) -> Option<Ref<B, T>> {
+        Ref::new(bytes)
+    }
+
+    /// Constructs a new `Ref` from the prefix of a byte slice for a type with
+    /// no alignment requirement.
+    ///
+    /// `new_unaligned_from_prefix` verifies that `bytes.len() >=
+    /// size_of::<T>()`. It consumes the first `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the remaining bytes to the
+    /// caller. If the length check fails, it returns `None`.
+    #[inline(always)]
+    pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref<B, T>, B)> {
+        Ref::new_from_prefix(bytes)
+    }
+
+    /// Constructs a new `Ref` from the suffix of a byte slice for a type with
+    /// no alignment requirement.
+    ///
+    /// `new_unaligned_from_suffix` verifies that `bytes.len() >=
+    /// size_of::<T>()`. It consumes the last `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the preceding bytes to the
+    /// caller. If the length check fails, it returns `None`.
+    #[inline(always)]
+    pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref<B, T>)> {
+        Ref::new_from_suffix(bytes)
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: Unaligned,
+{
+    /// Constructs a new `Ref` of a slice type with no alignment requirement.
+    ///
+    /// `new_slice_unaligned` verifies that `bytes.len()` is a multiple of
+    /// `size_of::<T>()` and constructs a new `Ref`. If the check fails, it
+    /// returns `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_unaligned(bytes: B) -> Option<Ref<B, [T]>> {
+        Ref::new_slice(bytes)
+    }
+
+    /// Constructs a new `Ref` of a slice type with no alignment requirement
+    /// from the prefix of a byte slice.
+    ///
+    /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count`. It consumes the first `size_of::<T>() * count` bytes from
+    /// `bytes` to construct a `Ref`, and returns the remaining bytes to the
+    /// caller. It also ensures that `sizeof::<T>() * count` does not overflow a
+    /// `usize`. If either the length, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_unaligned_from_prefix` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
+        Ref::new_slice_from_prefix(bytes, count)
+    }
+
+    /// Constructs a new `Ref` of a slice type with no alignment requirement
+    /// from the suffix of a byte slice.
+    ///
+    /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count`. It consumes the last `size_of::<T>() * count` bytes from `bytes`
+    /// to construct a `Ref`, and returns the remaining bytes to the caller. It
+    /// also ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If either the length, or overflow checks fail, it returns `None`.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_unaligned_from_suffix` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
+        Ref::new_slice_from_suffix(bytes, count)
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSliceMut,
+    T: Unaligned,
+{
+    /// Constructs a new `Ref` for a type with no alignment requirement, zeroing
+    /// the bytes.
+    ///
+    /// `new_unaligned_zeroed` verifies that `bytes.len() == size_of::<T>()` and
+    /// constructs a new `Ref`. If the check fails, it returns `None`.
+    ///
+    /// If the check succeeds, then `bytes` will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_unaligned_zeroed(bytes: B) -> Option<Ref<B, T>> {
+        map_zeroed(Self::new_unaligned(bytes))
+    }
+
+    /// Constructs a new `Ref` from the prefix of a byte slice for a type with
+    /// no alignment requirement, zeroing the prefix.
+    ///
+    /// `new_unaligned_from_prefix_zeroed` verifies that `bytes.len() >=
+    /// size_of::<T>()`. It consumes the first `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the remaining bytes to the
+    /// caller. If the length check fails, it returns `None`.
+    ///
+    /// If the check succeeds, then the prefix which is consumed will be
+    /// initialized to zero. This can be useful when re-using buffers to ensure
+    /// that sensitive data previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_unaligned_from_prefix_zeroed(bytes: B) -> Option<(Ref<B, T>, B)> {
+        map_prefix_tuple_zeroed(Self::new_unaligned_from_prefix(bytes))
+    }
+
+    /// Constructs a new `Ref` from the suffix of a byte slice for a type with
+    /// no alignment requirement, zeroing the suffix.
+    ///
+    /// `new_unaligned_from_suffix_zeroed` verifies that `bytes.len() >=
+    /// size_of::<T>()`. It consumes the last `size_of::<T>()` bytes from
+    /// `bytes` to construct a `Ref`, and returns the preceding bytes to the
+    /// caller. If the length check fails, it returns `None`.
+    ///
+    /// If the check succeeds, then the suffix which is consumed will be
+    /// initialized to zero. This can be useful when re-using buffers to ensure
+    /// that sensitive data previously stored in the buffer is not leaked.
+    #[inline(always)]
+    pub fn new_unaligned_from_suffix_zeroed(bytes: B) -> Option<(B, Ref<B, T>)> {
+        map_suffix_tuple_zeroed(Self::new_unaligned_from_suffix(bytes))
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSliceMut,
+    T: Unaligned,
+{
+    /// Constructs a new `Ref` for a slice type with no alignment requirement,
+    /// zeroing the bytes.
+    ///
+    /// `new_slice_unaligned_zeroed` verifies that `bytes.len()` is a multiple
+    /// of `size_of::<T>()` and constructs a new `Ref`. If the check fails, it
+    /// returns `None`.
+    ///
+    /// If the check succeeds, then `bytes` will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice` panics if `T` is a zero-sized type.
+    #[inline(always)]
+    pub fn new_slice_unaligned_zeroed(bytes: B) -> Option<Ref<B, [T]>> {
+        map_zeroed(Self::new_slice_unaligned(bytes))
+    }
+
+    /// Constructs a new `Ref` of a slice type with no alignment requirement
+    /// from the prefix of a byte slice, after zeroing the bytes.
+    ///
+    /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count`. It consumes the first `size_of::<T>() * count` bytes from
+    /// `bytes` to construct a `Ref`, and returns the remaining bytes to the
+    /// caller. It also ensures that `sizeof::<T>() * count` does not overflow a
+    /// `usize`. If either the length, or overflow checks fail, it returns
+    /// `None`.
+    ///
+    /// If the checks succeed, then the prefix will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_unaligned_from_prefix_zeroed` panics if `T` is a zero-sized
+    /// type.
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_prefix_zeroed(
+        bytes: B,
+        count: usize,
+    ) -> Option<(Ref<B, [T]>, B)> {
+        map_prefix_tuple_zeroed(Self::new_slice_unaligned_from_prefix(bytes, count))
+    }
+
+    /// Constructs a new `Ref` of a slice type with no alignment requirement
+    /// from the suffix of a byte slice, after zeroing the bytes.
+    ///
+    /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::<T>() *
+    /// count`. It consumes the last `size_of::<T>() * count` bytes from `bytes`
+    /// to construct a `Ref`, and returns the remaining bytes to the caller. It
+    /// also ensures that `sizeof::<T>() * count` does not overflow a `usize`.
+    /// If either the length, or overflow checks fail, it returns `None`.
+    ///
+    /// If the checks succeed, then the suffix will be initialized to zero. This
+    /// can be useful when re-using buffers to ensure that sensitive data
+    /// previously stored in the buffer is not leaked.
+    ///
+    /// # Panics
+    ///
+    /// `new_slice_unaligned_from_suffix_zeroed` panics if `T` is a zero-sized
+    /// type.
+    #[inline(always)]
+    pub fn new_slice_unaligned_from_suffix_zeroed(
+        bytes: B,
+        count: usize,
+    ) -> Option<(B, Ref<B, [T]>)> {
+        map_suffix_tuple_zeroed(Self::new_slice_unaligned_from_suffix(bytes, count))
+    }
+}
+
+impl<'a, B, T> Ref<B, T>
+where
+    B: 'a + ByteSlice,
+    T: FromBytes,
+{
+    /// Converts this `Ref` into a reference.
+    ///
+    /// `into_ref` consumes the `Ref`, and returns a reference to `T`.
+    #[inline(always)]
+    pub fn into_ref(self) -> &'a T {
+        assert!(B::INTO_REF_INTO_MUT_ARE_SOUND);
+
+        // SAFETY: According to the safety preconditions on
+        // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert
+        // ensures that, given `B: 'a`, it is sound to drop `self` and still
+        // access the underlying memory using reads for `'a`.
+        unsafe { self.deref_helper() }
+    }
+}
+
+impl<'a, B, T> Ref<B, T>
+where
+    B: 'a + ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    /// Converts this `Ref` into a mutable reference.
+    ///
+    /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`.
+    #[inline(always)]
+    pub fn into_mut(mut self) -> &'a mut T {
+        assert!(B::INTO_REF_INTO_MUT_ARE_SOUND);
+
+        // SAFETY: According to the safety preconditions on
+        // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert
+        // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop
+        // `self` and still access the underlying memory using both reads and
+        // writes for `'a`.
+        unsafe { self.deref_mut_helper() }
+    }
+}
+
+impl<'a, B, T> Ref<B, [T]>
+where
+    B: 'a + ByteSlice,
+    T: FromBytes,
+{
+    /// Converts this `Ref` into a slice reference.
+    ///
+    /// `into_slice` consumes the `Ref`, and returns a reference to `[T]`.
+    #[inline(always)]
+    pub fn into_slice(self) -> &'a [T] {
+        assert!(B::INTO_REF_INTO_MUT_ARE_SOUND);
+
+        // SAFETY: According to the safety preconditions on
+        // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert
+        // ensures that, given `B: 'a`, it is sound to drop `self` and still
+        // access the underlying memory using reads for `'a`.
+        unsafe { self.deref_slice_helper() }
+    }
+}
+
+impl<'a, B, T> Ref<B, [T]>
+where
+    B: 'a + ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    /// Converts this `Ref` into a mutable slice reference.
+    ///
+    /// `into_mut_slice` consumes the `Ref`, and returns a mutable reference to
+    /// `[T]`.
+    #[inline(always)]
+    pub fn into_mut_slice(mut self) -> &'a mut [T] {
+        assert!(B::INTO_REF_INTO_MUT_ARE_SOUND);
+
+        // SAFETY: According to the safety preconditions on
+        // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert
+        // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop
+        // `self` and still access the underlying memory using both reads and
+        // writes for `'a`.
+        unsafe { self.deref_mut_slice_helper() }
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes,
+{
+    /// Creates an immutable reference to `T` with a specific lifetime.
+    ///
+    /// # Safety
+    ///
+    /// The type bounds on this method guarantee that it is safe to create an
+    /// immutable reference to `T` from `self`. However, since the lifetime `'a`
+    /// is not required to be shorter than the lifetime of the reference to
+    /// `self`, the caller must guarantee that the lifetime `'a` is valid for
+    /// this reference. In particular, the referent must exist for all of `'a`,
+    /// and no mutable references to the same memory may be constructed during
+    /// `'a`.
+    unsafe fn deref_helper<'a>(&self) -> &'a T {
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            &*self.0.as_ptr().cast::<T>()
+        }
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    /// Creates a mutable reference to `T` with a specific lifetime.
+    ///
+    /// # Safety
+    ///
+    /// The type bounds on this method guarantee that it is safe to create a
+    /// mutable reference to `T` from `self`. However, since the lifetime `'a`
+    /// is not required to be shorter than the lifetime of the reference to
+    /// `self`, the caller must guarantee that the lifetime `'a` is valid for
+    /// this reference. In particular, the referent must exist for all of `'a`,
+    /// and no other references - mutable or immutable - to the same memory may
+    /// be constructed during `'a`.
+    unsafe fn deref_mut_helper<'a>(&mut self) -> &'a mut T {
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            &mut *self.0.as_mut_ptr().cast::<T>()
+        }
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes,
+{
+    /// Creates an immutable reference to `[T]` with a specific lifetime.
+    ///
+    /// # Safety
+    ///
+    /// `deref_slice_helper` has the same safety requirements as `deref_helper`.
+    unsafe fn deref_slice_helper<'a>(&self) -> &'a [T] {
+        let len = self.0.len();
+        let elem_size = mem::size_of::<T>();
+        debug_assert_ne!(elem_size, 0);
+        // `Ref<_, [T]>` maintains the invariant that `size_of::<T>() > 0`.
+        // Thus, neither the mod nor division operations here can panic.
+        #[allow(clippy::arithmetic_side_effects)]
+        let elems = {
+            debug_assert_eq!(len % elem_size, 0);
+            len / elem_size
+        };
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            slice::from_raw_parts(self.0.as_ptr().cast::<T>(), elems)
+        }
+    }
+}
+
+impl<B, T> Ref<B, [T]>
+where
+    B: ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    /// Creates a mutable reference to `[T]` with a specific lifetime.
+    ///
+    /// # Safety
+    ///
+    /// `deref_mut_slice_helper` has the same safety requirements as
+    /// `deref_mut_helper`.
+    unsafe fn deref_mut_slice_helper<'a>(&mut self) -> &'a mut [T] {
+        let len = self.0.len();
+        let elem_size = mem::size_of::<T>();
+        debug_assert_ne!(elem_size, 0);
+        // `Ref<_, [T]>` maintains the invariant that `size_of::<T>() > 0`.
+        // Thus, neither the mod nor division operations here can panic.
+        #[allow(clippy::arithmetic_side_effects)]
+        let elems = {
+            debug_assert_eq!(len % elem_size, 0);
+            len / elem_size
+        };
+        // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+        #[allow(clippy::undocumented_unsafe_blocks)]
+        unsafe {
+            slice::from_raw_parts_mut(self.0.as_mut_ptr().cast::<T>(), elems)
+        }
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSlice,
+    T: ?Sized,
+{
+    /// Gets the underlying bytes.
+    #[inline]
+    pub fn bytes(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSliceMut,
+    T: ?Sized,
+{
+    /// Gets the underlying bytes mutably.
+    #[inline]
+    pub fn bytes_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes,
+{
+    /// Reads a copy of `T`.
+    #[inline]
+    pub fn read(&self) -> T {
+        // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is
+        // at least `size_of::<T>()` bytes long, and that it is at least as
+        // aligned as `align_of::<T>()`. Because `T: FromBytes`, it is sound to
+        // interpret these bytes as a `T`.
+        unsafe { ptr::read(self.0.as_ptr().cast::<T>()) }
+    }
+}
+
+impl<B, T> Ref<B, T>
+where
+    B: ByteSliceMut,
+    T: AsBytes,
+{
+    /// Writes the bytes of `t` and then forgets `t`.
+    #[inline]
+    pub fn write(&mut self, t: T) {
+        // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is
+        // at least `size_of::<T>()` bytes long, and that it is at least as
+        // aligned as `align_of::<T>()`. Writing `t` to the buffer will allow
+        // all of the bytes of `t` to be accessed as a `[u8]`, but because `T:
+        // AsBytes`, we know this is sound.
+        unsafe { ptr::write(self.0.as_mut_ptr().cast::<T>(), t) }
+    }
+}
+
+impl<B, T> Deref for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes,
+{
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &T {
+        // SAFETY: This is sound because the lifetime of `self` is the same as
+        // the lifetime of the return value, meaning that a) the returned
+        // reference cannot outlive `self` and, b) no mutable methods on `self`
+        // can be called during the lifetime of the returned reference. See the
+        // documentation on `deref_helper` for what invariants we are required
+        // to uphold.
+        unsafe { self.deref_helper() }
+    }
+}
+
+impl<B, T> DerefMut for Ref<B, T>
+where
+    B: ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    #[inline]
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: This is sound because the lifetime of `self` is the same as
+        // the lifetime of the return value, meaning that a) the returned
+        // reference cannot outlive `self` and, b) no other methods on `self`
+        // can be called during the lifetime of the returned reference. See the
+        // documentation on `deref_mut_helper` for what invariants we are
+        // required to uphold.
+        unsafe { self.deref_mut_helper() }
+    }
+}
+
+impl<B, T> Deref for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes,
+{
+    type Target = [T];
+    #[inline]
+    fn deref(&self) -> &[T] {
+        // SAFETY: This is sound because the lifetime of `self` is the same as
+        // the lifetime of the return value, meaning that a) the returned
+        // reference cannot outlive `self` and, b) no mutable methods on `self`
+        // can be called during the lifetime of the returned reference. See the
+        // documentation on `deref_slice_helper` for what invariants we are
+        // required to uphold.
+        unsafe { self.deref_slice_helper() }
+    }
+}
+
+impl<B, T> DerefMut for Ref<B, [T]>
+where
+    B: ByteSliceMut,
+    T: FromBytes + AsBytes,
+{
+    #[inline]
+    fn deref_mut(&mut self) -> &mut [T] {
+        // SAFETY: This is sound because the lifetime of `self` is the same as
+        // the lifetime of the return value, meaning that a) the returned
+        // reference cannot outlive `self` and, b) no other methods on `self`
+        // can be called during the lifetime of the returned reference. See the
+        // documentation on `deref_mut_slice_helper` for what invariants we are
+        // required to uphold.
+        unsafe { self.deref_mut_slice_helper() }
+    }
+}
+
+impl<T, B> Display for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + Display,
+{
+    #[inline]
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        let inner: &T = self;
+        inner.fmt(fmt)
+    }
+}
+
+impl<T, B> Display for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes,
+    [T]: Display,
+{
+    #[inline]
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        let inner: &[T] = self;
+        inner.fmt(fmt)
+    }
+}
+
+impl<T, B> Debug for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + Debug,
+{
+    #[inline]
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        let inner: &T = self;
+        fmt.debug_tuple("Ref").field(&inner).finish()
+    }
+}
+
+impl<T, B> Debug for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes + Debug,
+{
+    #[inline]
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        let inner: &[T] = self;
+        fmt.debug_tuple("Ref").field(&inner).finish()
+    }
+}
+
+impl<T, B> Eq for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + Eq,
+{
+}
+
+impl<T, B> Eq for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes + Eq,
+{
+}
+
+impl<T, B> PartialEq for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + PartialEq,
+{
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.deref().eq(other.deref())
+    }
+}
+
+impl<T, B> PartialEq for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes + PartialEq,
+{
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.deref().eq(other.deref())
+    }
+}
+
+impl<T, B> Ord for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + Ord,
+{
+    #[inline]
+    fn cmp(&self, other: &Self) -> Ordering {
+        let inner: &T = self;
+        let other_inner: &T = other;
+        inner.cmp(other_inner)
+    }
+}
+
+impl<T, B> Ord for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes + Ord,
+{
+    #[inline]
+    fn cmp(&self, other: &Self) -> Ordering {
+        let inner: &[T] = self;
+        let other_inner: &[T] = other;
+        inner.cmp(other_inner)
+    }
+}
+
+impl<T, B> PartialOrd for Ref<B, T>
+where
+    B: ByteSlice,
+    T: FromBytes + PartialOrd,
+{
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        let inner: &T = self;
+        let other_inner: &T = other;
+        inner.partial_cmp(other_inner)
+    }
+}
+
+impl<T, B> PartialOrd for Ref<B, [T]>
+where
+    B: ByteSlice,
+    T: FromBytes + PartialOrd,
+{
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        let inner: &[T] = self;
+        let other_inner: &[T] = other;
+        inner.partial_cmp(other_inner)
+    }
+}
+
+mod sealed {
+    pub trait ByteSliceSealed {}
+}
+
+// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8],
+// Ref<[u8]>, RefMut<[u8]>, etc). We rely on various behaviors of these
+// references such as that a given reference will never changes its length
+// between calls to deref() or deref_mut(), and that split_at() works as
+// expected. If ByteSlice or ByteSliceMut were not sealed, consumers could
+// implement them in a way that violated these behaviors, and would break our
+// unsafe code. Thus, we seal them and implement it only for known-good
+// reference types. For the same reason, they're unsafe traits.
+
+#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068)
+/// A mutable or immutable reference to a byte slice.
+///
+/// `ByteSlice` abstracts over the mutability of a byte slice reference, and is
+/// implemented for various special reference types such as `Ref<[u8]>` and
+/// `RefMut<[u8]>`.
+///
+/// Note that, while it would be technically possible, `ByteSlice` is not
+/// implemented for [`Vec<u8>`], as the only way to implement the [`split_at`]
+/// method would involve reallocation, and `split_at` must be a very cheap
+/// operation in order for the utilities in this crate to perform as designed.
+///
+/// [`split_at`]: crate::ByteSlice::split_at
+// It may seem overkill to go to this length to ensure that this doc link never
+// breaks. We do this because it simplifies CI - it means that generating docs
+// always succeeds, so we don't need special logic to only generate docs under
+// certain features.
+#[cfg_attr(feature = "alloc", doc = "[`Vec<u8>`]: alloc::vec::Vec")]
+#[cfg_attr(
+    not(feature = "alloc"),
+    doc = "[`Vec<u8>`]: https://doc.rust-lang.org/std/vec/struct.Vec.html"
+)]
+pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized + sealed::ByteSliceSealed {
+    /// Are the [`Ref::into_ref`] and [`Ref::into_mut`] methods sound when used
+    /// with `Self`? If not, evaluating this constant must panic at compile
+    /// time.
+    ///
+    /// This exists to work around #716 on versions of zerocopy prior to 0.8.
+    ///
+    /// # Safety
+    ///
+    /// This may only be set to true if the following holds: Given the
+    /// following:
+    /// - `Self: 'a`
+    /// - `bytes: Self`
+    /// - `let ptr = bytes.as_ptr()`
+    ///
+    /// ...then:
+    /// - Using `ptr` to read the memory previously addressed by `bytes` is
+    ///   sound for `'a` even after `bytes` has been dropped.
+    /// - If `Self: ByteSliceMut`, using `ptr` to write the memory previously
+    ///   addressed by `bytes` is sound for `'a` even after `bytes` has been
+    ///   dropped.
+    #[doc(hidden)]
+    const INTO_REF_INTO_MUT_ARE_SOUND: bool;
+
+    /// Gets a raw pointer to the first byte in the slice.
+    #[inline]
+    fn as_ptr(&self) -> *const u8 {
+        <[u8]>::as_ptr(self)
+    }
+
+    /// Splits the slice at the midpoint.
+    ///
+    /// `x.split_at(mid)` returns `x[..mid]` and `x[mid..]`.
+    ///
+    /// # Panics
+    ///
+    /// `x.split_at(mid)` panics if `mid > x.len()`.
+    fn split_at(self, mid: usize) -> (Self, Self);
+}
+
+#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068)
+/// A mutable reference to a byte slice.
+///
+/// `ByteSliceMut` abstracts over various ways of storing a mutable reference to
+/// a byte slice, and is implemented for various special reference types such as
+/// `RefMut<[u8]>`.
+pub unsafe trait ByteSliceMut: ByteSlice + DerefMut {
+    /// Gets a mutable raw pointer to the first byte in the slice.
+    #[inline]
+    fn as_mut_ptr(&mut self) -> *mut u8 {
+        <[u8]>::as_mut_ptr(self)
+    }
+}
+
+impl<'a> sealed::ByteSliceSealed for &'a [u8] {}
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSlice for &'a [u8] {
+    // SAFETY: If `&'b [u8]: 'a`, then the underlying memory is treated as
+    // borrowed immutably for `'a` even if the slice itself is dropped.
+    const INTO_REF_INTO_MUT_ARE_SOUND: bool = true;
+
+    #[inline]
+    fn split_at(self, mid: usize) -> (Self, Self) {
+        <[u8]>::split_at(self, mid)
+    }
+}
+
+impl<'a> sealed::ByteSliceSealed for &'a mut [u8] {}
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSlice for &'a mut [u8] {
+    // SAFETY: If `&'b mut [u8]: 'a`, then the underlying memory is treated as
+    // borrowed mutably for `'a` even if the slice itself is dropped.
+    const INTO_REF_INTO_MUT_ARE_SOUND: bool = true;
+
+    #[inline]
+    fn split_at(self, mid: usize) -> (Self, Self) {
+        <[u8]>::split_at_mut(self, mid)
+    }
+}
+
+impl<'a> sealed::ByteSliceSealed for cell::Ref<'a, [u8]> {}
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> {
+    const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) {
+        panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::Ref; see https://github.com/google/zerocopy/issues/716")
+    } else {
+        // When compiling documentation, allow the evaluation of this constant
+        // to succeed. This doesn't represent a soundness hole - it just delays
+        // any error to runtime. The reason we need this is that, otherwise,
+        // `rustdoc` will fail when trying to document this item.
+        false
+    };
+
+    #[inline]
+    fn split_at(self, mid: usize) -> (Self, Self) {
+        cell::Ref::map_split(self, |slice| <[u8]>::split_at(slice, mid))
+    }
+}
+
+impl<'a> sealed::ByteSliceSealed for RefMut<'a, [u8]> {}
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSlice for RefMut<'a, [u8]> {
+    const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) {
+        panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::RefMut; see https://github.com/google/zerocopy/issues/716")
+    } else {
+        // When compiling documentation, allow the evaluation of this constant
+        // to succeed. This doesn't represent a soundness hole - it just delays
+        // any error to runtime. The reason we need this is that, otherwise,
+        // `rustdoc` will fail when trying to document this item.
+        false
+    };
+
+    #[inline]
+    fn split_at(self, mid: usize) -> (Self, Self) {
+        RefMut::map_split(self, |slice| <[u8]>::split_at_mut(slice, mid))
+    }
+}
+
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSliceMut for &'a mut [u8] {}
+
+// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
+#[allow(clippy::undocumented_unsafe_blocks)]
+unsafe impl<'a> ByteSliceMut for RefMut<'a, [u8]> {}
+
+#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+mod alloc_support {
+    use alloc::vec::Vec;
+
+    use super::*;
+
+    /// Extends a `Vec<T>` by pushing `additional` new items onto the end of the
+    /// vector. The new items are initialized with zeroes.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `Vec::reserve(additional)` fails to reserve enough memory.
+    #[inline(always)]
+    pub fn extend_vec_zeroed<T: FromZeroes>(v: &mut Vec<T>, additional: usize) {
+        insert_vec_zeroed(v, v.len(), additional);
+    }
+
+    /// Inserts `additional` new items into `Vec<T>` at `position`.
+    /// The new items are initialized with zeroes.
+    ///
+    /// # Panics
+    ///
+    /// * Panics if `position > v.len()`.
+    /// * Panics if `Vec::reserve(additional)` fails to reserve enough memory.
+    #[inline]
+    pub fn insert_vec_zeroed<T: FromZeroes>(v: &mut Vec<T>, position: usize, additional: usize) {
+        assert!(position <= v.len());
+        v.reserve(additional);
+        // SAFETY: The `reserve` call guarantees that these cannot overflow:
+        // * `ptr.add(position)`
+        // * `position + additional`
+        // * `v.len() + additional`
+        //
+        // `v.len() - position` cannot overflow because we asserted that
+        // `position <= v.len()`.
+        unsafe {
+            // This is a potentially overlapping copy.
+            let ptr = v.as_mut_ptr();
+            #[allow(clippy::arithmetic_side_effects)]
+            ptr.add(position).copy_to(ptr.add(position + additional), v.len() - position);
+            ptr.add(position).write_bytes(0, additional);
+            #[allow(clippy::arithmetic_side_effects)]
+            v.set_len(v.len() + additional);
+        }
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use core::convert::TryFrom as _;
+
+        use super::*;
+
+        #[test]
+        fn test_extend_vec_zeroed() {
+            // Test extending when there is an existing allocation.
+            let mut v = vec![100u64, 200, 300];
+            extend_vec_zeroed(&mut v, 3);
+            assert_eq!(v.len(), 6);
+            assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]);
+            drop(v);
+
+            // Test extending when there is no existing allocation.
+            let mut v: Vec<u64> = Vec::new();
+            extend_vec_zeroed(&mut v, 3);
+            assert_eq!(v.len(), 3);
+            assert_eq!(&*v, &[0, 0, 0]);
+            drop(v);
+        }
+
+        #[test]
+        fn test_extend_vec_zeroed_zst() {
+            // Test extending when there is an existing (fake) allocation.
+            let mut v = vec![(), (), ()];
+            extend_vec_zeroed(&mut v, 3);
+            assert_eq!(v.len(), 6);
+            assert_eq!(&*v, &[(), (), (), (), (), ()]);
+            drop(v);
+
+            // Test extending when there is no existing (fake) allocation.
+            let mut v: Vec<()> = Vec::new();
+            extend_vec_zeroed(&mut v, 3);
+            assert_eq!(&*v, &[(), (), ()]);
+            drop(v);
+        }
+
+        #[test]
+        fn test_insert_vec_zeroed() {
+            // Insert at start (no existing allocation).
+            let mut v: Vec<u64> = Vec::new();
+            insert_vec_zeroed(&mut v, 0, 2);
+            assert_eq!(v.len(), 2);
+            assert_eq!(&*v, &[0, 0]);
+            drop(v);
+
+            // Insert at start.
+            let mut v = vec![100u64, 200, 300];
+            insert_vec_zeroed(&mut v, 0, 2);
+            assert_eq!(v.len(), 5);
+            assert_eq!(&*v, &[0, 0, 100, 200, 300]);
+            drop(v);
+
+            // Insert at middle.
+            let mut v = vec![100u64, 200, 300];
+            insert_vec_zeroed(&mut v, 1, 1);
+            assert_eq!(v.len(), 4);
+            assert_eq!(&*v, &[100, 0, 200, 300]);
+            drop(v);
+
+            // Insert at end.
+            let mut v = vec![100u64, 200, 300];
+            insert_vec_zeroed(&mut v, 3, 1);
+            assert_eq!(v.len(), 4);
+            assert_eq!(&*v, &[100, 200, 300, 0]);
+            drop(v);
+        }
+
+        #[test]
+        fn test_insert_vec_zeroed_zst() {
+            // Insert at start (no existing fake allocation).
+            let mut v: Vec<()> = Vec::new();
+            insert_vec_zeroed(&mut v, 0, 2);
+            assert_eq!(v.len(), 2);
+            assert_eq!(&*v, &[(), ()]);
+            drop(v);
+
+            // Insert at start.
+            let mut v = vec![(), (), ()];
+            insert_vec_zeroed(&mut v, 0, 2);
+            assert_eq!(v.len(), 5);
+            assert_eq!(&*v, &[(), (), (), (), ()]);
+            drop(v);
+
+            // Insert at middle.
+            let mut v = vec![(), (), ()];
+            insert_vec_zeroed(&mut v, 1, 1);
+            assert_eq!(v.len(), 4);
+            assert_eq!(&*v, &[(), (), (), ()]);
+            drop(v);
+
+            // Insert at end.
+            let mut v = vec![(), (), ()];
+            insert_vec_zeroed(&mut v, 3, 1);
+            assert_eq!(v.len(), 4);
+            assert_eq!(&*v, &[(), (), (), ()]);
+            drop(v);
+        }
+
+        #[test]
+        fn test_new_box_zeroed() {
+            assert_eq!(*u64::new_box_zeroed(), 0);
+        }
+
+        #[test]
+        fn test_new_box_zeroed_array() {
+            drop(<[u32; 0x1000]>::new_box_zeroed());
+        }
+
+        #[test]
+        fn test_new_box_zeroed_zst() {
+            // This test exists in order to exercise unsafe code, especially
+            // when running under Miri.
+            #[allow(clippy::unit_cmp)]
+            {
+                assert_eq!(*<()>::new_box_zeroed(), ());
+            }
+        }
+
+        #[test]
+        fn test_new_box_slice_zeroed() {
+            let mut s: Box<[u64]> = u64::new_box_slice_zeroed(3);
+            assert_eq!(s.len(), 3);
+            assert_eq!(&*s, &[0, 0, 0]);
+            s[1] = 3;
+            assert_eq!(&*s, &[0, 3, 0]);
+        }
+
+        #[test]
+        fn test_new_box_slice_zeroed_empty() {
+            let s: Box<[u64]> = u64::new_box_slice_zeroed(0);
+            assert_eq!(s.len(), 0);
+        }
+
+        #[test]
+        fn test_new_box_slice_zeroed_zst() {
+            let mut s: Box<[()]> = <()>::new_box_slice_zeroed(3);
+            assert_eq!(s.len(), 3);
+            assert!(s.get(10).is_none());
+            // This test exists in order to exercise unsafe code, especially
+            // when running under Miri.
+            #[allow(clippy::unit_cmp)]
+            {
+                assert_eq!(s[1], ());
+            }
+            s[2] = ();
+        }
+
+        #[test]
+        fn test_new_box_slice_zeroed_zst_empty() {
+            let s: Box<[()]> = <()>::new_box_slice_zeroed(0);
+            assert_eq!(s.len(), 0);
+        }
+
+        #[test]
+        #[should_panic(expected = "mem::size_of::<Self>() * len overflows `usize`")]
+        fn test_new_box_slice_zeroed_panics_mul_overflow() {
+            let _ = u16::new_box_slice_zeroed(usize::MAX);
+        }
+
+        #[test]
+        #[should_panic(expected = "assertion failed: size <= max_alloc")]
+        fn test_new_box_slice_zeroed_panics_isize_overflow() {
+            let max = usize::try_from(isize::MAX).unwrap();
+            let _ = u16::new_box_slice_zeroed((max / mem::size_of::<u16>()) + 1);
+        }
+    }
+}
+
+#[cfg(feature = "alloc")]
+#[doc(inline)]
+pub use alloc_support::*;
+
+#[cfg(test)]
+mod tests {
+    #![allow(clippy::unreadable_literal)]
+
+    use core::{cell::UnsafeCell, convert::TryInto as _, ops::Deref};
+
+    use static_assertions::assert_impl_all;
+
+    use super::*;
+    use crate::util::testutil::*;
+
+    // An unsized type.
+    //
+    // This is used to test the custom derives of our traits. The `[u8]` type
+    // gets a hand-rolled impl, so it doesn't exercise our custom derives.
+    #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes, Unaligned)]
+    #[repr(transparent)]
+    struct Unsized([u8]);
+
+    impl Unsized {
+        fn from_mut_slice(slc: &mut [u8]) -> &mut Unsized {
+            // SAFETY: This *probably* sound - since the layouts of `[u8]` and
+            // `Unsized` are the same, so are the layouts of `&mut [u8]` and
+            // `&mut Unsized`. [1] Even if it turns out that this isn't actually
+            // guaranteed by the language spec, we can just change this since
+            // it's in test code.
+            //
+            // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/375
+            unsafe { mem::transmute(slc) }
+        }
+    }
+
+    /// Tests of when a sized `DstLayout` is extended with a sized field.
+    #[allow(clippy::decimal_literal_representation)]
+    #[test]
+    fn test_dst_layout_extend_sized_with_sized() {
+        // This macro constructs a layout corresponding to a `u8` and extends it
+        // with a zero-sized trailing field of given alignment `n`. The macro
+        // tests that the resulting layout has both size and alignment `min(n,
+        // P)` for all valid values of `repr(packed(P))`.
+        macro_rules! test_align_is_size {
+            ($n:expr) => {
+                let base = DstLayout::for_type::<u8>();
+                let trailing_field = DstLayout::for_type::<elain::Align<$n>>();
+
+                let packs =
+                    core::iter::once(None).chain((0..29).map(|p| NonZeroUsize::new(2usize.pow(p))));
+
+                for pack in packs {
+                    let composite = base.extend(trailing_field, pack);
+                    let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN);
+                    let align = $n.min(max_align.get());
+                    assert_eq!(
+                        composite,
+                        DstLayout {
+                            align: NonZeroUsize::new(align).unwrap(),
+                            size_info: SizeInfo::Sized { _size: align }
+                        }
+                    )
+                }
+            };
+        }
+
+        test_align_is_size!(1);
+        test_align_is_size!(2);
+        test_align_is_size!(4);
+        test_align_is_size!(8);
+        test_align_is_size!(16);
+        test_align_is_size!(32);
+        test_align_is_size!(64);
+        test_align_is_size!(128);
+        test_align_is_size!(256);
+        test_align_is_size!(512);
+        test_align_is_size!(1024);
+        test_align_is_size!(2048);
+        test_align_is_size!(4096);
+        test_align_is_size!(8192);
+        test_align_is_size!(16384);
+        test_align_is_size!(32768);
+        test_align_is_size!(65536);
+        test_align_is_size!(131072);
+        test_align_is_size!(262144);
+        test_align_is_size!(524288);
+        test_align_is_size!(1048576);
+        test_align_is_size!(2097152);
+        test_align_is_size!(4194304);
+        test_align_is_size!(8388608);
+        test_align_is_size!(16777216);
+        test_align_is_size!(33554432);
+        test_align_is_size!(67108864);
+        test_align_is_size!(33554432);
+        test_align_is_size!(134217728);
+        test_align_is_size!(268435456);
+    }
+
+    /// Tests of when a sized `DstLayout` is extended with a DST field.
+    #[test]
+    fn test_dst_layout_extend_sized_with_dst() {
+        // Test that for all combinations of real-world alignments and
+        // `repr_packed` values, that the extension of a sized `DstLayout`` with
+        // a DST field correctly computes the trailing offset in the composite
+        // layout.
+
+        let aligns = (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap());
+        let packs = core::iter::once(None).chain(aligns.clone().map(Some));
+
+        for align in aligns {
+            for pack in packs.clone() {
+                let base = DstLayout::for_type::<u8>();
+                let elem_size = 42;
+                let trailing_field_offset = 11;
+
+                let trailing_field = DstLayout {
+                    align,
+                    size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                        _elem_size: elem_size,
+                        _offset: 11,
+                    }),
+                };
+
+                let composite = base.extend(trailing_field, pack);
+
+                let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN).get();
+
+                let align = align.get().min(max_align);
+
+                assert_eq!(
+                    composite,
+                    DstLayout {
+                        align: NonZeroUsize::new(align).unwrap(),
+                        size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                            _elem_size: elem_size,
+                            _offset: align + trailing_field_offset,
+                        }),
+                    }
+                )
+            }
+        }
+    }
+
+    /// Tests that calling `pad_to_align` on a sized `DstLayout` adds the
+    /// expected amount of trailing padding.
+    #[test]
+    fn test_dst_layout_pad_to_align_with_sized() {
+        // For all valid alignments `align`, construct a one-byte layout aligned
+        // to `align`, call `pad_to_align`, and assert that the size of the
+        // resulting layout is equal to `align`.
+        for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) {
+            let layout = DstLayout { align, size_info: SizeInfo::Sized { _size: 1 } };
+
+            assert_eq!(
+                layout.pad_to_align(),
+                DstLayout { align, size_info: SizeInfo::Sized { _size: align.get() } }
+            );
+        }
+
+        // Test explicitly-provided combinations of unpadded and padded
+        // counterparts.
+
+        macro_rules! test {
+            (unpadded { size: $unpadded_size:expr, align: $unpadded_align:expr }
+                => padded { size: $padded_size:expr, align: $padded_align:expr }) => {
+                let unpadded = DstLayout {
+                    align: NonZeroUsize::new($unpadded_align).unwrap(),
+                    size_info: SizeInfo::Sized { _size: $unpadded_size },
+                };
+                let padded = unpadded.pad_to_align();
+
+                assert_eq!(
+                    padded,
+                    DstLayout {
+                        align: NonZeroUsize::new($padded_align).unwrap(),
+                        size_info: SizeInfo::Sized { _size: $padded_size },
+                    }
+                );
+            };
+        }
+
+        test!(unpadded { size: 0, align: 4 } => padded { size: 0, align: 4 });
+        test!(unpadded { size: 1, align: 4 } => padded { size: 4, align: 4 });
+        test!(unpadded { size: 2, align: 4 } => padded { size: 4, align: 4 });
+        test!(unpadded { size: 3, align: 4 } => padded { size: 4, align: 4 });
+        test!(unpadded { size: 4, align: 4 } => padded { size: 4, align: 4 });
+        test!(unpadded { size: 5, align: 4 } => padded { size: 8, align: 4 });
+        test!(unpadded { size: 6, align: 4 } => padded { size: 8, align: 4 });
+        test!(unpadded { size: 7, align: 4 } => padded { size: 8, align: 4 });
+        test!(unpadded { size: 8, align: 4 } => padded { size: 8, align: 4 });
+
+        let current_max_align = DstLayout::CURRENT_MAX_ALIGN.get();
+
+        test!(unpadded { size: 1, align: current_max_align }
+            => padded { size: current_max_align, align: current_max_align });
+
+        test!(unpadded { size: current_max_align + 1, align: current_max_align }
+            => padded { size: current_max_align * 2, align: current_max_align });
+    }
+
+    /// Tests that calling `pad_to_align` on a DST `DstLayout` is a no-op.
+    #[test]
+    fn test_dst_layout_pad_to_align_with_dst() {
+        for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) {
+            for offset in 0..10 {
+                for elem_size in 0..10 {
+                    let layout = DstLayout {
+                        align,
+                        size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                            _offset: offset,
+                            _elem_size: elem_size,
+                        }),
+                    };
+                    assert_eq!(layout.pad_to_align(), layout);
+                }
+            }
+        }
+    }
+
+    // This test takes a long time when running under Miri, so we skip it in
+    // that case. This is acceptable because this is a logic test that doesn't
+    // attempt to expose UB.
+    #[test]
+    #[cfg_attr(miri, ignore)]
+    fn testvalidate_cast_and_convert_metadata() {
+        impl From<usize> for SizeInfo {
+            fn from(_size: usize) -> SizeInfo {
+                SizeInfo::Sized { _size }
+            }
+        }
+
+        impl From<(usize, usize)> for SizeInfo {
+            fn from((_offset, _elem_size): (usize, usize)) -> SizeInfo {
+                SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size })
+            }
+        }
+
+        fn layout<S: Into<SizeInfo>>(s: S, align: usize) -> DstLayout {
+            DstLayout { size_info: s.into(), align: NonZeroUsize::new(align).unwrap() }
+        }
+
+        /// This macro accepts arguments in the form of:
+        ///
+        ///           layout(_, _, _).validate(_, _, _), Ok(Some((_, _)))
+        ///                  |  |  |           |  |  |            |  |
+        ///    base_size ----+  |  |           |  |  |            |  |
+        ///    align -----------+  |           |  |  |            |  |
+        ///    trailing_size ------+           |  |  |            |  |
+        ///    addr ---------------------------+  |  |            |  |
+        ///    bytes_len -------------------------+  |            |  |
+        ///    cast_type ----------------------------+            |  |
+        ///    elems ---------------------------------------------+  |
+        ///    split_at ---------------------------------------------+
+        ///
+        /// `.validate` is shorthand for `.validate_cast_and_convert_metadata`
+        /// for brevity.
+        ///
+        /// Each argument can either be an iterator or a wildcard. Each
+        /// wildcarded variable is implicitly replaced by an iterator over a
+        /// representative sample of values for that variable. Each `test!`
+        /// invocation iterates over every combination of values provided by
+        /// each variable's iterator (ie, the cartesian product) and validates
+        /// that the results are expected.
+        ///
+        /// The final argument uses the same syntax, but it has a different
+        /// meaning:
+        /// - If it is `Ok(pat)`, then the pattern `pat` is supplied to
+        ///   `assert_matches!` to validate the computed result for each
+        ///   combination of input values.
+        /// - If it is `Err(msg)`, then `test!` validates that the call to
+        ///   `validate_cast_and_convert_metadata` panics with the given panic
+        ///   message.
+        ///
+        /// Note that the meta-variables that match these variables have the
+        /// `tt` type, and some valid expressions are not valid `tt`s (such as
+        /// `a..b`). In this case, wrap the expression in parentheses, and it
+        /// will become valid `tt`.
+        macro_rules! test {
+            ($(:$sizes:expr =>)?
+                layout($size:tt, $align:tt)
+                .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)?
+            ) => {
+                itertools::iproduct!(
+                    test!(@generate_size $size),
+                    test!(@generate_align $align),
+                    test!(@generate_usize $addr),
+                    test!(@generate_usize $bytes_len),
+                    test!(@generate_cast_type $cast_type)
+                ).for_each(|(size_info, align, addr, bytes_len, cast_type)| {
+                    // Temporarily disable the panic hook installed by the test
+                    // harness. If we don't do this, all panic messages will be
+                    // kept in an internal log. On its own, this isn't a
+                    // problem, but if a non-caught panic ever happens (ie, in
+                    // code later in this test not in this macro), all of the
+                    // previously-buffered messages will be dumped, hiding the
+                    // real culprit.
+                    let previous_hook = std::panic::take_hook();
+                    // I don't understand why, but this seems to be required in
+                    // addition to the previous line.
+                    std::panic::set_hook(Box::new(|_| {}));
+                    let actual = std::panic::catch_unwind(|| {
+                        layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type)
+                    }).map_err(|d| {
+                        *d.downcast::<&'static str>().expect("expected string panic message").as_ref()
+                    });
+                    std::panic::set_hook(previous_hook);
+
+                    assert_matches::assert_matches!(
+                        actual, $expect,
+                        "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?})",
+                    );
+                });
+            };
+            (@generate_usize _) => { 0..8 };
+            // Generate sizes for both Sized and !Sized types.
+            (@generate_size _) => {
+                test!(@generate_size (_)).chain(test!(@generate_size (_, _)))
+            };
+            // Generate sizes for both Sized and !Sized types by chaining
+            // specified iterators for each.
+            (@generate_size ($sized_sizes:tt | $unsized_sizes:tt)) => {
+                test!(@generate_size ($sized_sizes)).chain(test!(@generate_size $unsized_sizes))
+            };
+            // Generate sizes for Sized types.
+            (@generate_size (_)) => { test!(@generate_size (0..8)) };
+            (@generate_size ($sizes:expr)) => { $sizes.into_iter().map(Into::<SizeInfo>::into) };
+            // Generate sizes for !Sized types.
+            (@generate_size ($min_sizes:tt, $elem_sizes:tt)) => {
+                itertools::iproduct!(
+                    test!(@generate_min_size $min_sizes),
+                    test!(@generate_elem_size $elem_sizes)
+                ).map(Into::<SizeInfo>::into)
+            };
+            (@generate_fixed_size _) => { (0..8).into_iter().map(Into::<SizeInfo>::into) };
+            (@generate_min_size _) => { 0..8 };
+            (@generate_elem_size _) => { 1..8 };
+            (@generate_align _) => { [1, 2, 4, 8, 16] };
+            (@generate_opt_usize _) => { [None].into_iter().chain((0..8).map(Some).into_iter()) };
+            (@generate_cast_type _) => { [_CastType::_Prefix, _CastType::_Suffix] };
+            (@generate_cast_type $variant:ident) => { [_CastType::$variant] };
+            // Some expressions need to be wrapped in parentheses in order to be
+            // valid `tt`s (required by the top match pattern). See the comment
+            // below for more details. This arm removes these parentheses to
+            // avoid generating an `unused_parens` warning.
+            (@$_:ident ($vals:expr)) => { $vals };
+            (@$_:ident $vals:expr) => { $vals };
+        }
+
+        const EVENS: [usize; 8] = [0, 2, 4, 6, 8, 10, 12, 14];
+        const ODDS: [usize; 8] = [1, 3, 5, 7, 9, 11, 13, 15];
+
+        // base_size is too big for the memory region.
+        test!(layout(((1..8) | ((1..8), (1..8))), _).validate(_, [0], _), Ok(None));
+        test!(layout(((2..8) | ((2..8), (2..8))), _).validate(_, [1], _), Ok(None));
+
+        // addr is unaligned for prefix cast
+        test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None));
+        test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None));
+
+        // addr is aligned, but end of buffer is unaligned for suffix cast
+        test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None));
+        test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None));
+
+        // Unfortunately, these constants cannot easily be used in the
+        // implementation of `validate_cast_and_convert_metadata`, since
+        // `panic!` consumes a string literal, not an expression.
+        //
+        // It's important that these messages be in a separate module. If they
+        // were at the function's top level, we'd pass them to `test!` as, e.g.,
+        // `Err(TRAILING)`, which would run into a subtle Rust footgun - the
+        // `TRAILING` identifier would be treated as a pattern to match rather
+        // than a value to check for equality.
+        mod msgs {
+            pub(super) const TRAILING: &str =
+                "attempted to cast to slice type with zero-sized element";
+            pub(super) const OVERFLOW: &str = "`addr` + `bytes_len` > usize::MAX";
+        }
+
+        // casts with ZST trailing element types are unsupported
+        test!(layout((_, [0]), _).validate(_, _, _), Err(msgs::TRAILING),);
+
+        // addr + bytes_len must not overflow usize
+        test!(layout(_, _).validate([usize::MAX], (1..100), _), Err(msgs::OVERFLOW));
+        test!(layout(_, _).validate((1..100), [usize::MAX], _), Err(msgs::OVERFLOW));
+        test!(
+            layout(_, _).validate(
+                [usize::MAX / 2 + 1, usize::MAX],
+                [usize::MAX / 2 + 1, usize::MAX],
+                _
+            ),
+            Err(msgs::OVERFLOW)
+        );
+
+        // Validates that `validate_cast_and_convert_metadata` satisfies its own
+        // documented safety postconditions, and also a few other properties
+        // that aren't documented but we want to guarantee anyway.
+        fn validate_behavior(
+            (layout, addr, bytes_len, cast_type): (DstLayout, usize, usize, _CastType),
+        ) {
+            if let Some((elems, split_at)) =
+                layout.validate_cast_and_convert_metadata(addr, bytes_len, cast_type)
+            {
+                let (size_info, align) = (layout.size_info, layout.align);
+                let debug_str = format!(
+                    "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?}) => ({elems}, {split_at})",
+                );
+
+                // If this is a sized type (no trailing slice), then `elems` is
+                // meaningless, but in practice we set it to 0. Callers are not
+                // allowed to rely on this, but a lot of math is nicer if
+                // they're able to, and some callers might accidentally do that.
+                let sized = matches!(layout.size_info, SizeInfo::Sized { .. });
+                assert!(!(sized && elems != 0), "{}", debug_str);
+
+                let resulting_size = match layout.size_info {
+                    SizeInfo::Sized { _size } => _size,
+                    SizeInfo::SliceDst(TrailingSliceLayout {
+                        _offset: offset,
+                        _elem_size: elem_size,
+                    }) => {
+                        let padded_size = |elems| {
+                            let without_padding = offset + elems * elem_size;
+                            without_padding
+                                + util::core_layout::padding_needed_for(without_padding, align)
+                        };
+
+                        let resulting_size = padded_size(elems);
+                        // Test that `validate_cast_and_convert_metadata`
+                        // computed the largest possible value that fits in the
+                        // given range.
+                        assert!(padded_size(elems + 1) > bytes_len, "{}", debug_str);
+                        resulting_size
+                    }
+                };
+
+                // Test safety postconditions guaranteed by
+                // `validate_cast_and_convert_metadata`.
+                assert!(resulting_size <= bytes_len, "{}", debug_str);
+                match cast_type {
+                    _CastType::_Prefix => {
+                        assert_eq!(addr % align, 0, "{}", debug_str);
+                        assert_eq!(resulting_size, split_at, "{}", debug_str);
+                    }
+                    _CastType::_Suffix => {
+                        assert_eq!(split_at, bytes_len - resulting_size, "{}", debug_str);
+                        assert_eq!((addr + split_at) % align, 0, "{}", debug_str);
+                    }
+                }
+            } else {
+                let min_size = match layout.size_info {
+                    SizeInfo::Sized { _size } => _size,
+                    SizeInfo::SliceDst(TrailingSliceLayout { _offset, .. }) => {
+                        _offset + util::core_layout::padding_needed_for(_offset, layout.align)
+                    }
+                };
+
+                // If a cast is invalid, it is either because...
+                // 1. there are insufficent bytes at the given region for type:
+                let insufficient_bytes = bytes_len < min_size;
+                // 2. performing the cast would misalign type:
+                let base = match cast_type {
+                    _CastType::_Prefix => 0,
+                    _CastType::_Suffix => bytes_len,
+                };
+                let misaligned = (base + addr) % layout.align != 0;
+
+                assert!(insufficient_bytes || misaligned);
+            }
+        }
+
+        let sizes = 0..8;
+        let elem_sizes = 1..8;
+        let size_infos = sizes
+            .clone()
+            .map(Into::<SizeInfo>::into)
+            .chain(itertools::iproduct!(sizes, elem_sizes).map(Into::<SizeInfo>::into));
+        let layouts = itertools::iproduct!(size_infos, [1, 2, 4, 8, 16, 32])
+            .filter(|(size_info, align)| !matches!(size_info, SizeInfo::Sized { _size } if _size % align != 0))
+            .map(|(size_info, align)| layout(size_info, align));
+        itertools::iproduct!(layouts, 0..8, 0..8, [_CastType::_Prefix, _CastType::_Suffix])
+            .for_each(validate_behavior);
+    }
+
+    #[test]
+    #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+    fn test_validate_rust_layout() {
+        use core::ptr::NonNull;
+
+        // This test synthesizes pointers with various metadata and uses Rust's
+        // built-in APIs to confirm that Rust makes decisions about type layout
+        // which are consistent with what we believe is guaranteed by the
+        // language. If this test fails, it doesn't just mean our code is wrong
+        // - it means we're misunderstanding the language's guarantees.
+
+        #[derive(Debug)]
+        struct MacroArgs {
+            offset: usize,
+            align: NonZeroUsize,
+            elem_size: Option<usize>,
+        }
+
+        /// # Safety
+        ///
+        /// `test` promises to only call `addr_of_slice_field` on a `NonNull<T>`
+        /// which points to a valid `T`.
+        ///
+        /// `with_elems` must produce a pointer which points to a valid `T`.
+        fn test<T: ?Sized, W: Fn(usize) -> NonNull<T>>(
+            args: MacroArgs,
+            with_elems: W,
+            addr_of_slice_field: Option<fn(NonNull<T>) -> NonNull<u8>>,
+        ) {
+            let dst = args.elem_size.is_some();
+            let layout = {
+                let size_info = match args.elem_size {
+                    Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout {
+                        _offset: args.offset,
+                        _elem_size: elem_size,
+                    }),
+                    None => SizeInfo::Sized {
+                        // Rust only supports types whose sizes are a multiple
+                        // of their alignment. If the macro created a type like
+                        // this:
+                        //
+                        //   #[repr(C, align(2))]
+                        //   struct Foo([u8; 1]);
+                        //
+                        // ...then Rust will automatically round the type's size
+                        // up to 2.
+                        _size: args.offset
+                            + util::core_layout::padding_needed_for(args.offset, args.align),
+                    },
+                };
+                DstLayout { size_info, align: args.align }
+            };
+
+            for elems in 0..128 {
+                let ptr = with_elems(elems);
+
+                if let Some(addr_of_slice_field) = addr_of_slice_field {
+                    let slc_field_ptr = addr_of_slice_field(ptr).as_ptr();
+                    // SAFETY: Both `slc_field_ptr` and `ptr` are pointers to
+                    // the same valid Rust object.
+                    let offset: usize =
+                        unsafe { slc_field_ptr.byte_offset_from(ptr.as_ptr()).try_into().unwrap() };
+                    assert_eq!(offset, args.offset);
+                }
+
+                // SAFETY: `ptr` points to a valid `T`.
+                let (size, align) = unsafe {
+                    (mem::size_of_val_raw(ptr.as_ptr()), mem::align_of_val_raw(ptr.as_ptr()))
+                };
+
+                // Avoid expensive allocation when running under Miri.
+                let assert_msg = if !cfg!(miri) {
+                    format!("\n{args:?}\nsize:{size}, align:{align}")
+                } else {
+                    String::new()
+                };
+
+                let without_padding =
+                    args.offset + args.elem_size.map(|elem_size| elems * elem_size).unwrap_or(0);
+                assert!(size >= without_padding, "{}", assert_msg);
+                assert_eq!(align, args.align.get(), "{}", assert_msg);
+
+                // This encodes the most important part of the test: our
+                // understanding of how Rust determines the layout of repr(C)
+                // types. Sized repr(C) types are trivial, but DST types have
+                // some subtlety. Note that:
+                // - For sized types, `without_padding` is just the size of the
+                //   type that we constructed for `Foo`. Since we may have
+                //   requested a larger alignment, `Foo` may actually be larger
+                //   than this, hence `padding_needed_for`.
+                // - For unsized types, `without_padding` is dynamically
+                //   computed from the offset, the element size, and element
+                //   count. We expect that the size of the object should be
+                //   `offset + elem_size * elems` rounded up to the next
+                //   alignment.
+                let expected_size = without_padding
+                    + util::core_layout::padding_needed_for(without_padding, args.align);
+                assert_eq!(expected_size, size, "{}", assert_msg);
+
+                // For zero-sized element types,
+                // `validate_cast_and_convert_metadata` just panics, so we skip
+                // testing those types.
+                if args.elem_size.map(|elem_size| elem_size > 0).unwrap_or(true) {
+                    let addr = ptr.addr().get();
+                    let (got_elems, got_split_at) = layout
+                        .validate_cast_and_convert_metadata(addr, size, _CastType::_Prefix)
+                        .unwrap();
+                    // Avoid expensive allocation when running under Miri.
+                    let assert_msg = if !cfg!(miri) {
+                        format!(
+                            "{}\nvalidate_cast_and_convert_metadata({addr}, {size})",
+                            assert_msg
+                        )
+                    } else {
+                        String::new()
+                    };
+                    assert_eq!(got_split_at, size, "{}", assert_msg);
+                    if dst {
+                        assert!(got_elems >= elems, "{}", assert_msg);
+                        if got_elems != elems {
+                            // If `validate_cast_and_convert_metadata`
+                            // returned more elements than `elems`, that
+                            // means that `elems` is not the maximum number
+                            // of elements that can fit in `size` - in other
+                            // words, there is enough padding at the end of
+                            // the value to fit at least one more element.
+                            // If we use this metadata to synthesize a
+                            // pointer, despite having a different element
+                            // count, we still expect it to have the same
+                            // size.
+                            let got_ptr = with_elems(got_elems);
+                            // SAFETY: `got_ptr` is a pointer to a valid `T`.
+                            let size_of_got_ptr = unsafe { mem::size_of_val_raw(got_ptr.as_ptr()) };
+                            assert_eq!(size_of_got_ptr, size, "{}", assert_msg);
+                        }
+                    } else {
+                        // For sized casts, the returned element value is
+                        // technically meaningless, and we don't guarantee any
+                        // particular value. In practice, it's always zero.
+                        assert_eq!(got_elems, 0, "{}", assert_msg)
+                    }
+                }
+            }
+        }
+
+        macro_rules! validate_against_rust {
+            ($offset:literal, $align:literal $(, $elem_size:literal)?) => {{
+                #[repr(C, align($align))]
+                struct Foo([u8; $offset]$(, [[u8; $elem_size]])?);
+
+                let args = MacroArgs {
+                    offset: $offset,
+                    align: $align.try_into().unwrap(),
+                    elem_size: {
+                        #[allow(unused)]
+                        let ret = None::<usize>;
+                        $(let ret = Some($elem_size);)?
+                        ret
+                    }
+                };
+
+                #[repr(C, align($align))]
+                struct FooAlign;
+                // Create an aligned buffer to use in order to synthesize
+                // pointers to `Foo`. We don't ever load values from these
+                // pointers - we just do arithmetic on them - so having a "real"
+                // block of memory as opposed to a validly-aligned-but-dangling
+                // pointer is only necessary to make Miri happy since we run it
+                // with "strict provenance" checking enabled.
+                let aligned_buf = Align::<_, FooAlign>::new([0u8; 1024]);
+                let with_elems = |elems| {
+                    let slc = NonNull::slice_from_raw_parts(NonNull::from(&aligned_buf.t), elems);
+                    #[allow(clippy::as_conversions)]
+                    NonNull::new(slc.as_ptr() as *mut Foo).unwrap()
+                };
+                let addr_of_slice_field = {
+                    #[allow(unused)]
+                    let f = None::<fn(NonNull<Foo>) -> NonNull<u8>>;
+                    $(
+                        // SAFETY: `test` promises to only call `f` with a `ptr`
+                        // to a valid `Foo`.
+                        let f: Option<fn(NonNull<Foo>) -> NonNull<u8>> = Some(|ptr: NonNull<Foo>| unsafe {
+                            NonNull::new(ptr::addr_of_mut!((*ptr.as_ptr()).1)).unwrap().cast::<u8>()
+                        });
+                        let _ = $elem_size;
+                    )?
+                    f
+                };
+
+                test::<Foo, _>(args, with_elems, addr_of_slice_field);
+            }};
+        }
+
+        // Every permutation of:
+        // - offset in [0, 4]
+        // - align in [1, 16]
+        // - elem_size in [0, 4] (plus no elem_size)
+        validate_against_rust!(0, 1);
+        validate_against_rust!(0, 1, 0);
+        validate_against_rust!(0, 1, 1);
+        validate_against_rust!(0, 1, 2);
+        validate_against_rust!(0, 1, 3);
+        validate_against_rust!(0, 1, 4);
+        validate_against_rust!(0, 2);
+        validate_against_rust!(0, 2, 0);
+        validate_against_rust!(0, 2, 1);
+        validate_against_rust!(0, 2, 2);
+        validate_against_rust!(0, 2, 3);
+        validate_against_rust!(0, 2, 4);
+        validate_against_rust!(0, 4);
+        validate_against_rust!(0, 4, 0);
+        validate_against_rust!(0, 4, 1);
+        validate_against_rust!(0, 4, 2);
+        validate_against_rust!(0, 4, 3);
+        validate_against_rust!(0, 4, 4);
+        validate_against_rust!(0, 8);
+        validate_against_rust!(0, 8, 0);
+        validate_against_rust!(0, 8, 1);
+        validate_against_rust!(0, 8, 2);
+        validate_against_rust!(0, 8, 3);
+        validate_against_rust!(0, 8, 4);
+        validate_against_rust!(0, 16);
+        validate_against_rust!(0, 16, 0);
+        validate_against_rust!(0, 16, 1);
+        validate_against_rust!(0, 16, 2);
+        validate_against_rust!(0, 16, 3);
+        validate_against_rust!(0, 16, 4);
+        validate_against_rust!(1, 1);
+        validate_against_rust!(1, 1, 0);
+        validate_against_rust!(1, 1, 1);
+        validate_against_rust!(1, 1, 2);
+        validate_against_rust!(1, 1, 3);
+        validate_against_rust!(1, 1, 4);
+        validate_against_rust!(1, 2);
+        validate_against_rust!(1, 2, 0);
+        validate_against_rust!(1, 2, 1);
+        validate_against_rust!(1, 2, 2);
+        validate_against_rust!(1, 2, 3);
+        validate_against_rust!(1, 2, 4);
+        validate_against_rust!(1, 4);
+        validate_against_rust!(1, 4, 0);
+        validate_against_rust!(1, 4, 1);
+        validate_against_rust!(1, 4, 2);
+        validate_against_rust!(1, 4, 3);
+        validate_against_rust!(1, 4, 4);
+        validate_against_rust!(1, 8);
+        validate_against_rust!(1, 8, 0);
+        validate_against_rust!(1, 8, 1);
+        validate_against_rust!(1, 8, 2);
+        validate_against_rust!(1, 8, 3);
+        validate_against_rust!(1, 8, 4);
+        validate_against_rust!(1, 16);
+        validate_against_rust!(1, 16, 0);
+        validate_against_rust!(1, 16, 1);
+        validate_against_rust!(1, 16, 2);
+        validate_against_rust!(1, 16, 3);
+        validate_against_rust!(1, 16, 4);
+        validate_against_rust!(2, 1);
+        validate_against_rust!(2, 1, 0);
+        validate_against_rust!(2, 1, 1);
+        validate_against_rust!(2, 1, 2);
+        validate_against_rust!(2, 1, 3);
+        validate_against_rust!(2, 1, 4);
+        validate_against_rust!(2, 2);
+        validate_against_rust!(2, 2, 0);
+        validate_against_rust!(2, 2, 1);
+        validate_against_rust!(2, 2, 2);
+        validate_against_rust!(2, 2, 3);
+        validate_against_rust!(2, 2, 4);
+        validate_against_rust!(2, 4);
+        validate_against_rust!(2, 4, 0);
+        validate_against_rust!(2, 4, 1);
+        validate_against_rust!(2, 4, 2);
+        validate_against_rust!(2, 4, 3);
+        validate_against_rust!(2, 4, 4);
+        validate_against_rust!(2, 8);
+        validate_against_rust!(2, 8, 0);
+        validate_against_rust!(2, 8, 1);
+        validate_against_rust!(2, 8, 2);
+        validate_against_rust!(2, 8, 3);
+        validate_against_rust!(2, 8, 4);
+        validate_against_rust!(2, 16);
+        validate_against_rust!(2, 16, 0);
+        validate_against_rust!(2, 16, 1);
+        validate_against_rust!(2, 16, 2);
+        validate_against_rust!(2, 16, 3);
+        validate_against_rust!(2, 16, 4);
+        validate_against_rust!(3, 1);
+        validate_against_rust!(3, 1, 0);
+        validate_against_rust!(3, 1, 1);
+        validate_against_rust!(3, 1, 2);
+        validate_against_rust!(3, 1, 3);
+        validate_against_rust!(3, 1, 4);
+        validate_against_rust!(3, 2);
+        validate_against_rust!(3, 2, 0);
+        validate_against_rust!(3, 2, 1);
+        validate_against_rust!(3, 2, 2);
+        validate_against_rust!(3, 2, 3);
+        validate_against_rust!(3, 2, 4);
+        validate_against_rust!(3, 4);
+        validate_against_rust!(3, 4, 0);
+        validate_against_rust!(3, 4, 1);
+        validate_against_rust!(3, 4, 2);
+        validate_against_rust!(3, 4, 3);
+        validate_against_rust!(3, 4, 4);
+        validate_against_rust!(3, 8);
+        validate_against_rust!(3, 8, 0);
+        validate_against_rust!(3, 8, 1);
+        validate_against_rust!(3, 8, 2);
+        validate_against_rust!(3, 8, 3);
+        validate_against_rust!(3, 8, 4);
+        validate_against_rust!(3, 16);
+        validate_against_rust!(3, 16, 0);
+        validate_against_rust!(3, 16, 1);
+        validate_against_rust!(3, 16, 2);
+        validate_against_rust!(3, 16, 3);
+        validate_against_rust!(3, 16, 4);
+        validate_against_rust!(4, 1);
+        validate_against_rust!(4, 1, 0);
+        validate_against_rust!(4, 1, 1);
+        validate_against_rust!(4, 1, 2);
+        validate_against_rust!(4, 1, 3);
+        validate_against_rust!(4, 1, 4);
+        validate_against_rust!(4, 2);
+        validate_against_rust!(4, 2, 0);
+        validate_against_rust!(4, 2, 1);
+        validate_against_rust!(4, 2, 2);
+        validate_against_rust!(4, 2, 3);
+        validate_against_rust!(4, 2, 4);
+        validate_against_rust!(4, 4);
+        validate_against_rust!(4, 4, 0);
+        validate_against_rust!(4, 4, 1);
+        validate_against_rust!(4, 4, 2);
+        validate_against_rust!(4, 4, 3);
+        validate_against_rust!(4, 4, 4);
+        validate_against_rust!(4, 8);
+        validate_against_rust!(4, 8, 0);
+        validate_against_rust!(4, 8, 1);
+        validate_against_rust!(4, 8, 2);
+        validate_against_rust!(4, 8, 3);
+        validate_against_rust!(4, 8, 4);
+        validate_against_rust!(4, 16);
+        validate_against_rust!(4, 16, 0);
+        validate_against_rust!(4, 16, 1);
+        validate_against_rust!(4, 16, 2);
+        validate_against_rust!(4, 16, 3);
+        validate_against_rust!(4, 16, 4);
+    }
+
+    #[test]
+    fn test_known_layout() {
+        // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout.
+        // Test that `PhantomData<$ty>` has the same layout as `()` regardless
+        // of `$ty`.
+        macro_rules! test {
+            ($ty:ty, $expect:expr) => {
+                let expect = $expect;
+                assert_eq!(<$ty as KnownLayout>::LAYOUT, expect);
+                assert_eq!(<ManuallyDrop<$ty> as KnownLayout>::LAYOUT, expect);
+                assert_eq!(<PhantomData<$ty> as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT);
+            };
+        }
+
+        let layout = |offset, align, _trailing_slice_elem_size| DstLayout {
+            align: NonZeroUsize::new(align).unwrap(),
+            size_info: match _trailing_slice_elem_size {
+                None => SizeInfo::Sized { _size: offset },
+                Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout {
+                    _offset: offset,
+                    _elem_size: elem_size,
+                }),
+            },
+        };
+
+        test!((), layout(0, 1, None));
+        test!(u8, layout(1, 1, None));
+        // Use `align_of` because `u64` alignment may be smaller than 8 on some
+        // platforms.
+        test!(u64, layout(8, mem::align_of::<u64>(), None));
+        test!(AU64, layout(8, 8, None));
+
+        test!(Option<&'static ()>, usize::LAYOUT);
+
+        test!([()], layout(0, 1, Some(0)));
+        test!([u8], layout(0, 1, Some(1)));
+        test!(str, layout(0, 1, Some(1)));
+    }
+
+    #[cfg(feature = "derive")]
+    #[test]
+    fn test_known_layout_derive() {
+        // In this and other files (`late_compile_pass.rs`,
+        // `mid_compile_pass.rs`, and `struct.rs`), we test success and failure
+        // modes of `derive(KnownLayout)` for the following combination of
+        // properties:
+        //
+        // +------------+--------------------------------------+-----------+
+        // |            |      trailing field properties       |           |
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |------------+----------+----------------+----------+-----------|
+        // |          N |        N |              N |        N |      KL00 |
+        // |          N |        N |              N |        Y |      KL01 |
+        // |          N |        N |              Y |        N |      KL02 |
+        // |          N |        N |              Y |        Y |      KL03 |
+        // |          N |        Y |              N |        N |      KL04 |
+        // |          N |        Y |              N |        Y |      KL05 |
+        // |          N |        Y |              Y |        N |      KL06 |
+        // |          N |        Y |              Y |        Y |      KL07 |
+        // |          Y |        N |              N |        N |      KL08 |
+        // |          Y |        N |              N |        Y |      KL09 |
+        // |          Y |        N |              Y |        N |      KL10 |
+        // |          Y |        N |              Y |        Y |      KL11 |
+        // |          Y |        Y |              N |        N |      KL12 |
+        // |          Y |        Y |              N |        Y |      KL13 |
+        // |          Y |        Y |              Y |        N |      KL14 |
+        // |          Y |        Y |              Y |        Y |      KL15 |
+        // +------------+----------+----------------+----------+-----------+
+
+        struct NotKnownLayout<T = ()> {
+            _t: T,
+        }
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct AlignSize<const ALIGN: usize, const SIZE: usize>
+        where
+            elain::Align<ALIGN>: elain::Alignment,
+        {
+            _align: elain::Align<ALIGN>,
+            _size: [u8; SIZE],
+        }
+
+        type AU16 = AlignSize<2, 2>;
+        type AU32 = AlignSize<4, 4>;
+
+        fn _assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
+
+        let sized_layout = |align, size| DstLayout {
+            align: NonZeroUsize::new(align).unwrap(),
+            size_info: SizeInfo::Sized { _size: size },
+        };
+
+        let unsized_layout = |align, elem_size, offset| DstLayout {
+            align: NonZeroUsize::new(align).unwrap(),
+            size_info: SizeInfo::SliceDst(TrailingSliceLayout {
+                _offset: offset,
+                _elem_size: elem_size,
+            }),
+        };
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        N |              N |        Y |      KL01 |
+        #[derive(KnownLayout)]
+        #[allow(dead_code)] // fields are never read
+        struct KL01(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01>();
+
+        assert_eq!(<KL01 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01 as KnownLayout>::LAYOUT, sized_layout(4, 8));
+
+        // ...with `align(N)`:
+        #[derive(KnownLayout)]
+        #[repr(align(64))]
+        #[allow(dead_code)] // fields are never read
+        struct KL01Align(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01Align>();
+
+        assert_eq!(<KL01Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ...with `packed`:
+        #[derive(KnownLayout)]
+        #[repr(packed)]
+        #[allow(dead_code)] // fields are never read
+        struct KL01Packed(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        let expected = DstLayout::for_type::<KL01Packed>();
+
+        assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01Packed as KnownLayout>::LAYOUT, sized_layout(1, 6));
+
+        // ...with `packed(N)`:
+        #[derive(KnownLayout)]
+        #[repr(packed(2))]
+        #[allow(dead_code)] // fields are never read
+        struct KL01PackedN(NotKnownLayout<AU32>, NotKnownLayout<AU16>);
+
+        assert_impl_all!(KL01PackedN: KnownLayout);
+
+        let expected = DstLayout::for_type::<KL01PackedN>();
+
+        assert_eq!(<KL01PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL01PackedN as KnownLayout>::LAYOUT, sized_layout(2, 6));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        N |              Y |        Y |      KL03 |
+        #[derive(KnownLayout)]
+        #[allow(dead_code)] // fields are never read
+        struct KL03(NotKnownLayout, u8);
+
+        let expected = DstLayout::for_type::<KL03>();
+
+        assert_eq!(<KL03 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03 as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        // ... with `align(N)`
+        #[derive(KnownLayout)]
+        #[repr(align(64))]
+        #[allow(dead_code)] // fields are never read
+        struct KL03Align(NotKnownLayout<AU32>, u8);
+
+        let expected = DstLayout::for_type::<KL03Align>();
+
+        assert_eq!(<KL03Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ... with `packed`:
+        #[derive(KnownLayout)]
+        #[repr(packed)]
+        #[allow(dead_code)] // fields are never read
+        struct KL03Packed(NotKnownLayout<AU32>, u8);
+
+        let expected = DstLayout::for_type::<KL03Packed>();
+
+        assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03Packed as KnownLayout>::LAYOUT, sized_layout(1, 5));
+
+        // ... with `packed(N)`
+        #[derive(KnownLayout)]
+        #[repr(packed(2))]
+        #[allow(dead_code)] // fields are never read
+        struct KL03PackedN(NotKnownLayout<AU32>, u8);
+
+        assert_impl_all!(KL03PackedN: KnownLayout);
+
+        let expected = DstLayout::for_type::<KL03PackedN>();
+
+        assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL03PackedN as KnownLayout>::LAYOUT, sized_layout(2, 6));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        Y |              N |        Y |      KL05 |
+        #[derive(KnownLayout)]
+        #[allow(dead_code)] // fields are never read
+        struct KL05<T>(u8, T);
+
+        fn _test_kl05<T>(t: T) -> impl KnownLayout {
+            KL05(0u8, t)
+        }
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          N |        Y |              Y |        Y |      KL07 |
+        #[derive(KnownLayout)]
+        #[allow(dead_code)] // fields are never read
+        struct KL07<T: KnownLayout>(u8, T);
+
+        fn _test_kl07<T: KnownLayout>(t: T) -> impl KnownLayout {
+            let _ = KL07(0u8, t);
+        }
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        N |              Y |        N |      KL10 |
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL10(NotKnownLayout<AU32>, [u8]);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None)
+            .extend(<[u8] as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL10 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 4));
+
+        // ...with `align(N)`:
+        #[derive(KnownLayout)]
+        #[repr(C, align(64))]
+        struct KL10Align(NotKnownLayout<AU32>, [u8]);
+
+        let repr_align = NonZeroUsize::new(64);
+
+        let expected = DstLayout::new_zst(repr_align)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), None)
+            .extend(<[u8] as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL10Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10Align as KnownLayout>::LAYOUT, unsized_layout(64, 1, 4));
+
+        // ...with `packed`:
+        #[derive(KnownLayout)]
+        #[repr(C, packed)]
+        struct KL10Packed(NotKnownLayout<AU32>, [u8]);
+
+        let repr_packed = NonZeroUsize::new(1);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed)
+            .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10Packed as KnownLayout>::LAYOUT, unsized_layout(1, 1, 4));
+
+        // ...with `packed(N)`:
+        #[derive(KnownLayout)]
+        #[repr(C, packed(2))]
+        struct KL10PackedN(NotKnownLayout<AU32>, [u8]);
+
+        let repr_packed = NonZeroUsize::new(2);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU32>>(), repr_packed)
+            .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL10PackedN as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        N |              Y |        Y |      KL11 |
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL11(NotKnownLayout<AU64>, u8);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None)
+            .extend(<u8 as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL11 as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11 as KnownLayout>::LAYOUT, sized_layout(8, 16));
+
+        // ...with `align(N)`:
+        #[derive(KnownLayout)]
+        #[repr(C, align(64))]
+        struct KL11Align(NotKnownLayout<AU64>, u8);
+
+        let repr_align = NonZeroUsize::new(64);
+
+        let expected = DstLayout::new_zst(repr_align)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), None)
+            .extend(<u8 as KnownLayout>::LAYOUT, None)
+            .pad_to_align();
+
+        assert_eq!(<KL11Align as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11Align as KnownLayout>::LAYOUT, sized_layout(64, 64));
+
+        // ...with `packed`:
+        #[derive(KnownLayout)]
+        #[repr(C, packed)]
+        struct KL11Packed(NotKnownLayout<AU64>, u8);
+
+        let repr_packed = NonZeroUsize::new(1);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed)
+            .extend(<u8 as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11Packed as KnownLayout>::LAYOUT, sized_layout(1, 9));
+
+        // ...with `packed(N)`:
+        #[derive(KnownLayout)]
+        #[repr(C, packed(2))]
+        struct KL11PackedN(NotKnownLayout<AU64>, u8);
+
+        let repr_packed = NonZeroUsize::new(2);
+
+        let expected = DstLayout::new_zst(None)
+            .extend(DstLayout::for_type::<NotKnownLayout<AU64>>(), repr_packed)
+            .extend(<u8 as KnownLayout>::LAYOUT, repr_packed)
+            .pad_to_align();
+
+        assert_eq!(<KL11PackedN as KnownLayout>::LAYOUT, expected);
+        assert_eq!(<KL11PackedN as KnownLayout>::LAYOUT, sized_layout(2, 10));
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        Y |              Y |        N |      KL14 |
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL14<T: ?Sized + KnownLayout>(u8, T);
+
+        fn _test_kl14<T: ?Sized + KnownLayout>(kl: &KL14<T>) {
+            _assert_kl(kl)
+        }
+
+        // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name |
+        // |          Y |        Y |              Y |        Y |      KL15 |
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KL15<T: KnownLayout>(u8, T);
+
+        fn _test_kl15<T: KnownLayout>(t: T) -> impl KnownLayout {
+            let _ = KL15(0u8, t);
+        }
+
+        // Test a variety of combinations of field types:
+        //  - ()
+        //  - u8
+        //  - AU16
+        //  - [()]
+        //  - [u8]
+        //  - [AU16]
+
+        #[allow(clippy::upper_case_acronyms)]
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLTU<T, U: ?Sized>(T, U);
+
+        assert_eq!(<KLTU<(), ()> as KnownLayout>::LAYOUT, sized_layout(1, 0));
+
+        assert_eq!(<KLTU<(), u8> as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        assert_eq!(<KLTU<(), AU16> as KnownLayout>::LAYOUT, sized_layout(2, 2));
+
+        assert_eq!(<KLTU<(), [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0));
+
+        assert_eq!(<KLTU<(), [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0));
+
+        assert_eq!(<KLTU<(), [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0));
+
+        assert_eq!(<KLTU<u8, ()> as KnownLayout>::LAYOUT, sized_layout(1, 1));
+
+        assert_eq!(<KLTU<u8, u8> as KnownLayout>::LAYOUT, sized_layout(1, 2));
+
+        assert_eq!(<KLTU<u8, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<u8, [()]> as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1));
+
+        assert_eq!(<KLTU<u8, [u8]> as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1));
+
+        assert_eq!(<KLTU<u8, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2));
+
+        assert_eq!(<KLTU<AU16, ()> as KnownLayout>::LAYOUT, sized_layout(2, 2));
+
+        assert_eq!(<KLTU<AU16, u8> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<AU16, AU16> as KnownLayout>::LAYOUT, sized_layout(2, 4));
+
+        assert_eq!(<KLTU<AU16, [()]> as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2));
+
+        assert_eq!(<KLTU<AU16, [u8]> as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2));
+
+        assert_eq!(<KLTU<AU16, [AU16]> as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2));
+
+        // Test a variety of field counts.
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF0;
+
+        assert_eq!(<KLF0 as KnownLayout>::LAYOUT, sized_layout(1, 0));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF1([u8]);
+
+        assert_eq!(<KLF1 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF2(NotKnownLayout<u8>, [u8]);
+
+        assert_eq!(<KLF2 as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF3(NotKnownLayout<u8>, NotKnownLayout<AU16>, [u8]);
+
+        assert_eq!(<KLF3 as KnownLayout>::LAYOUT, unsized_layout(2, 1, 4));
+
+        #[derive(KnownLayout)]
+        #[repr(C)]
+        struct KLF4(NotKnownLayout<u8>, NotKnownLayout<AU16>, NotKnownLayout<AU32>, [u8]);
+
+        assert_eq!(<KLF4 as KnownLayout>::LAYOUT, unsized_layout(4, 1, 8));
+    }
+
+    #[test]
+    fn test_object_safety() {
+        fn _takes_from_zeroes(_: &dyn FromZeroes) {}
+        fn _takes_from_bytes(_: &dyn FromBytes) {}
+        fn _takes_unaligned(_: &dyn Unaligned) {}
+    }
+
+    #[test]
+    fn test_from_zeroes_only() {
+        // Test types that implement `FromZeroes` but not `FromBytes`.
+
+        assert!(!bool::new_zeroed());
+        assert_eq!(char::new_zeroed(), '\0');
+
+        #[cfg(feature = "alloc")]
+        {
+            assert_eq!(bool::new_box_zeroed(), Box::new(false));
+            assert_eq!(char::new_box_zeroed(), Box::new('\0'));
+
+            assert_eq!(bool::new_box_slice_zeroed(3).as_ref(), [false, false, false]);
+            assert_eq!(char::new_box_slice_zeroed(3).as_ref(), ['\0', '\0', '\0']);
+
+            assert_eq!(bool::new_vec_zeroed(3).as_ref(), [false, false, false]);
+            assert_eq!(char::new_vec_zeroed(3).as_ref(), ['\0', '\0', '\0']);
+        }
+
+        let mut string = "hello".to_string();
+        let s: &mut str = string.as_mut();
+        assert_eq!(s, "hello");
+        s.zero();
+        assert_eq!(s, "\0\0\0\0\0");
+    }
+
+    #[test]
+    fn test_read_write() {
+        const VAL: u64 = 0x12345678;
+        #[cfg(target_endian = "big")]
+        const VAL_BYTES: [u8; 8] = VAL.to_be_bytes();
+        #[cfg(target_endian = "little")]
+        const VAL_BYTES: [u8; 8] = VAL.to_le_bytes();
+
+        // Test `FromBytes::{read_from, read_from_prefix, read_from_suffix}`.
+
+        assert_eq!(u64::read_from(&VAL_BYTES[..]), Some(VAL));
+        // The first 8 bytes are from `VAL_BYTES` and the second 8 bytes are all
+        // zeroes.
+        let bytes_with_prefix: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]);
+        assert_eq!(u64::read_from_prefix(&bytes_with_prefix[..]), Some(VAL));
+        assert_eq!(u64::read_from_suffix(&bytes_with_prefix[..]), Some(0));
+        // The first 8 bytes are all zeroes and the second 8 bytes are from
+        // `VAL_BYTES`
+        let bytes_with_suffix: [u8; 16] = transmute!([[0; 8], VAL_BYTES]);
+        assert_eq!(u64::read_from_prefix(&bytes_with_suffix[..]), Some(0));
+        assert_eq!(u64::read_from_suffix(&bytes_with_suffix[..]), Some(VAL));
+
+        // Test `AsBytes::{write_to, write_to_prefix, write_to_suffix}`.
+
+        let mut bytes = [0u8; 8];
+        assert_eq!(VAL.write_to(&mut bytes[..]), Some(()));
+        assert_eq!(bytes, VAL_BYTES);
+        let mut bytes = [0u8; 16];
+        assert_eq!(VAL.write_to_prefix(&mut bytes[..]), Some(()));
+        let want: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]);
+        assert_eq!(bytes, want);
+        let mut bytes = [0u8; 16];
+        assert_eq!(VAL.write_to_suffix(&mut bytes[..]), Some(()));
+        let want: [u8; 16] = transmute!([[0; 8], VAL_BYTES]);
+        assert_eq!(bytes, want);
+    }
+
+    #[test]
+    fn test_transmute() {
+        // Test that memory is transmuted as expected.
+        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
+        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
+        let x: [[u8; 2]; 4] = transmute!(array_of_u8s);
+        assert_eq!(x, array_of_arrays);
+        let x: [u8; 8] = transmute!(array_of_arrays);
+        assert_eq!(x, array_of_u8s);
+
+        // Test that the source expression's value is forgotten rather than
+        // dropped.
+        #[derive(AsBytes)]
+        #[repr(transparent)]
+        struct PanicOnDrop(());
+        impl Drop for PanicOnDrop {
+            fn drop(&mut self) {
+                panic!("PanicOnDrop::drop");
+            }
+        }
+        #[allow(clippy::let_unit_value)]
+        let _: () = transmute!(PanicOnDrop(()));
+
+        // Test that `transmute!` is legal in a const context.
+        const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
+        const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
+        const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S);
+        assert_eq!(X, ARRAY_OF_ARRAYS);
+    }
+
+    #[test]
+    fn test_transmute_ref() {
+        // Test that memory is transmuted as expected.
+        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
+        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
+        let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s);
+        assert_eq!(*x, array_of_arrays);
+        let x: &[u8; 8] = transmute_ref!(&array_of_arrays);
+        assert_eq!(*x, array_of_u8s);
+
+        // Test that `transmute_ref!` is legal in a const context.
+        const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
+        const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
+        #[allow(clippy::redundant_static_lifetimes)]
+        const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S);
+        assert_eq!(*X, ARRAY_OF_ARRAYS);
+
+        // Test that it's legal to transmute a reference while shrinking the
+        // lifetime (note that `X` has the lifetime `'static`).
+        let x: &[u8; 8] = transmute_ref!(X);
+        assert_eq!(*x, ARRAY_OF_U8S);
+
+        // Test that `transmute_ref!` supports decreasing alignment.
+        let u = AU64(0);
+        let array = [0, 0, 0, 0, 0, 0, 0, 0];
+        let x: &[u8; 8] = transmute_ref!(&u);
+        assert_eq!(*x, array);
+
+        // Test that a mutable reference can be turned into an immutable one.
+        let mut x = 0u8;
+        #[allow(clippy::useless_transmute)]
+        let y: &u8 = transmute_ref!(&mut x);
+        assert_eq!(*y, 0);
+    }
+
+    #[test]
+    fn test_transmute_mut() {
+        // Test that memory is transmuted as expected.
+        let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
+        let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
+        let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s);
+        assert_eq!(*x, array_of_arrays);
+        let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
+        assert_eq!(*x, array_of_u8s);
+
+        {
+            // Test that it's legal to transmute a reference while shrinking the
+            // lifetime.
+            let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
+            assert_eq!(*x, array_of_u8s);
+        }
+        // Test that `transmute_mut!` supports decreasing alignment.
+        let mut u = AU64(0);
+        let array = [0, 0, 0, 0, 0, 0, 0, 0];
+        let x: &[u8; 8] = transmute_mut!(&mut u);
+        assert_eq!(*x, array);
+
+        // Test that a mutable reference can be turned into an immutable one.
+        let mut x = 0u8;
+        #[allow(clippy::useless_transmute)]
+        let y: &u8 = transmute_mut!(&mut x);
+        assert_eq!(*y, 0);
+    }
+
+    #[test]
+    fn test_macros_evaluate_args_once() {
+        let mut ctr = 0;
+        let _: usize = transmute!({
+            ctr += 1;
+            0usize
+        });
+        assert_eq!(ctr, 1);
+
+        let mut ctr = 0;
+        let _: &usize = transmute_ref!({
+            ctr += 1;
+            &0usize
+        });
+        assert_eq!(ctr, 1);
+    }
+
+    #[test]
+    fn test_include_value() {
+        const AS_U32: u32 = include_value!("../testdata/include_value/data");
+        assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
+        const AS_I32: i32 = include_value!("../testdata/include_value/data");
+        assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
+    }
+
+    #[test]
+    fn test_address() {
+        // Test that the `Deref` and `DerefMut` implementations return a
+        // reference which points to the right region of memory.
+
+        let buf = [0];
+        let r = Ref::<_, u8>::new(&buf[..]).unwrap();
+        let buf_ptr = buf.as_ptr();
+        let deref_ptr: *const u8 = r.deref();
+        assert_eq!(buf_ptr, deref_ptr);
+
+        let buf = [0];
+        let r = Ref::<_, [u8]>::new_slice(&buf[..]).unwrap();
+        let buf_ptr = buf.as_ptr();
+        let deref_ptr = r.deref().as_ptr();
+        assert_eq!(buf_ptr, deref_ptr);
+    }
+
+    // Verify that values written to a `Ref` are properly shared between the
+    // typed and untyped representations, that reads via `deref` and `read`
+    // behave the same, and that writes via `deref_mut` and `write` behave the
+    // same.
+    fn test_new_helper(mut r: Ref<&mut [u8], AU64>) {
+        // assert that the value starts at 0
+        assert_eq!(*r, AU64(0));
+        assert_eq!(r.read(), AU64(0));
+
+        // Assert that values written to the typed value are reflected in the
+        // byte slice.
+        const VAL1: AU64 = AU64(0xFF00FF00FF00FF00);
+        *r = VAL1;
+        assert_eq!(r.bytes(), &VAL1.to_bytes());
+        *r = AU64(0);
+        r.write(VAL1);
+        assert_eq!(r.bytes(), &VAL1.to_bytes());
+
+        // Assert that values written to the byte slice are reflected in the
+        // typed value.
+        const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1`
+        r.bytes_mut().copy_from_slice(&VAL2.to_bytes()[..]);
+        assert_eq!(*r, VAL2);
+        assert_eq!(r.read(), VAL2);
+    }
+
+    // Verify that values written to a `Ref` are properly shared between the
+    // typed and untyped representations; pass a value with `typed_len` `AU64`s
+    // backed by an array of `typed_len * 8` bytes.
+    fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) {
+        // Assert that the value starts out zeroed.
+        assert_eq!(&*r, vec![AU64(0); typed_len].as_slice());
+
+        // Check the backing storage is the exact same slice.
+        let untyped_len = typed_len * 8;
+        assert_eq!(r.bytes().len(), untyped_len);
+        assert_eq!(r.bytes().as_ptr(), r.as_ptr().cast::<u8>());
+
+        // Assert that values written to the typed value are reflected in the
+        // byte slice.
+        const VAL1: AU64 = AU64(0xFF00FF00FF00FF00);
+        for typed in &mut *r {
+            *typed = VAL1;
+        }
+        assert_eq!(r.bytes(), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice());
+
+        // Assert that values written to the byte slice are reflected in the
+        // typed value.
+        const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1
+        r.bytes_mut().copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len));
+        assert!(r.iter().copied().all(|x| x == VAL2));
+    }
+
+    // Verify that values written to a `Ref` are properly shared between the
+    // typed and untyped representations, that reads via `deref` and `read`
+    // behave the same, and that writes via `deref_mut` and `write` behave the
+    // same.
+    fn test_new_helper_unaligned(mut r: Ref<&mut [u8], [u8; 8]>) {
+        // assert that the value starts at 0
+        assert_eq!(*r, [0; 8]);
+        assert_eq!(r.read(), [0; 8]);
+
+        // Assert that values written to the typed value are reflected in the
+        // byte slice.
+        const VAL1: [u8; 8] = [0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00];
+        *r = VAL1;
+        assert_eq!(r.bytes(), &VAL1);
+        *r = [0; 8];
+        r.write(VAL1);
+        assert_eq!(r.bytes(), &VAL1);
+
+        // Assert that values written to the byte slice are reflected in the
+        // typed value.
+        const VAL2: [u8; 8] = [0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF]; // different from VAL1
+        r.bytes_mut().copy_from_slice(&VAL2[..]);
+        assert_eq!(*r, VAL2);
+        assert_eq!(r.read(), VAL2);
+    }
+
+    // Verify that values written to a `Ref` are properly shared between the
+    // typed and untyped representations; pass a value with `len` `u8`s backed
+    // by an array of `len` bytes.
+    fn test_new_helper_slice_unaligned(mut r: Ref<&mut [u8], [u8]>, len: usize) {
+        // Assert that the value starts out zeroed.
+        assert_eq!(&*r, vec![0u8; len].as_slice());
+
+        // Check the backing storage is the exact same slice.
+        assert_eq!(r.bytes().len(), len);
+        assert_eq!(r.bytes().as_ptr(), r.as_ptr());
+
+        // Assert that values written to the typed value are reflected in the
+        // byte slice.
+        let mut expected_bytes = [0xFF, 0x00].iter().copied().cycle().take(len).collect::<Vec<_>>();
+        r.copy_from_slice(&expected_bytes);
+        assert_eq!(r.bytes(), expected_bytes.as_slice());
+
+        // Assert that values written to the byte slice are reflected in the
+        // typed value.
+        for byte in &mut expected_bytes {
+            *byte = !*byte; // different from `expected_len`
+        }
+        r.bytes_mut().copy_from_slice(&expected_bytes);
+        assert_eq!(&*r, expected_bytes.as_slice());
+    }
+
+    #[test]
+    fn test_new_aligned_sized() {
+        // Test that a properly-aligned, properly-sized buffer works for new,
+        // new_from_prefix, and new_from_suffix, and that new_from_prefix and
+        // new_from_suffix return empty slices. Test that a properly-aligned
+        // buffer whose length is a multiple of the element size works for
+        // new_slice. Test that xxx_zeroed behaves the same, and zeroes the
+        // memory.
+
+        // A buffer with an alignment of 8.
+        let mut buf = Align::<[u8; 8], AU64>::default();
+        // `buf.t` should be aligned to 8, so this should always succeed.
+        test_new_helper(Ref::<_, AU64>::new(&mut buf.t[..]).unwrap());
+        let ascending: [u8; 8] = (0..8).collect::<Vec<_>>().try_into().unwrap();
+        buf.t = ascending;
+        test_new_helper(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).unwrap());
+        {
+            // In a block so that `r` and `suffix` don't live too long.
+            buf.set_default();
+            let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap();
+            assert!(suffix.is_empty());
+            test_new_helper(r);
+        }
+        {
+            buf.t = ascending;
+            let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap();
+            assert!(suffix.is_empty());
+            test_new_helper(r);
+        }
+        {
+            buf.set_default();
+            let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap();
+            assert!(prefix.is_empty());
+            test_new_helper(r);
+        }
+        {
+            buf.t = ascending;
+            let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap();
+            assert!(prefix.is_empty());
+            test_new_helper(r);
+        }
+
+        // A buffer with alignment 8 and length 24. We choose this length very
+        // intentionally: if we instead used length 16, then the prefix and
+        // suffix lengths would be identical. In the past, we used length 16,
+        // which resulted in this test failing to discover the bug uncovered in
+        // #506.
+        let mut buf = Align::<[u8; 24], AU64>::default();
+        // `buf.t` should be aligned to 8 and have a length which is a multiple
+        // of `size_of::<AU64>()`, so this should always succeed.
+        test_new_helper_slice(Ref::<_, [AU64]>::new_slice(&mut buf.t[..]).unwrap(), 3);
+        let ascending: [u8; 24] = (0..24).collect::<Vec<_>>().try_into().unwrap();
+        // 16 ascending bytes followed by 8 zeros.
+        let mut ascending_prefix = ascending;
+        ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
+        // 8 zeros followed by 16 ascending bytes.
+        let mut ascending_suffix = ascending;
+        ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
+        test_new_helper_slice(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).unwrap(), 3);
+
+        {
+            buf.t = ascending_suffix;
+            let (r, suffix) = Ref::<_, [AU64]>::new_slice_from_prefix(&mut buf.t[..], 1).unwrap();
+            assert_eq!(suffix, &ascending[8..]);
+            test_new_helper_slice(r, 1);
+        }
+        {
+            buf.t = ascending_suffix;
+            let (r, suffix) =
+                Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 1).unwrap();
+            assert_eq!(suffix, &ascending[8..]);
+            test_new_helper_slice(r, 1);
+        }
+        {
+            buf.t = ascending_prefix;
+            let (prefix, r) = Ref::<_, [AU64]>::new_slice_from_suffix(&mut buf.t[..], 1).unwrap();
+            assert_eq!(prefix, &ascending[..16]);
+            test_new_helper_slice(r, 1);
+        }
+        {
+            buf.t = ascending_prefix;
+            let (prefix, r) =
+                Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 1).unwrap();
+            assert_eq!(prefix, &ascending[..16]);
+            test_new_helper_slice(r, 1);
+        }
+    }
+
+    #[test]
+    fn test_new_unaligned_sized() {
+        // Test that an unaligned, properly-sized buffer works for
+        // `new_unaligned`, `new_unaligned_from_prefix`, and
+        // `new_unaligned_from_suffix`, and that `new_unaligned_from_prefix`
+        // `new_unaligned_from_suffix` return empty slices. Test that an
+        // unaligned buffer whose length is a multiple of the element size works
+        // for `new_slice`. Test that `xxx_zeroed` behaves the same, and zeroes
+        // the memory.
+
+        let mut buf = [0u8; 8];
+        test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned(&mut buf[..]).unwrap());
+        buf = [0xFFu8; 8];
+        test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf[..]).unwrap());
+        {
+            // In a block so that `r` and `suffix` don't live too long.
+            buf = [0u8; 8];
+            let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap();
+            assert!(suffix.is_empty());
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0xFFu8; 8];
+            let (r, suffix) =
+                Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap();
+            assert!(suffix.is_empty());
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0u8; 8];
+            let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap();
+            assert!(prefix.is_empty());
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0xFFu8; 8];
+            let (prefix, r) =
+                Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap();
+            assert!(prefix.is_empty());
+            test_new_helper_unaligned(r);
+        }
+
+        let mut buf = [0u8; 16];
+        // `buf.t` should be aligned to 8 and have a length which is a multiple
+        // of `size_of::AU64>()`, so this should always succeed.
+        test_new_helper_slice_unaligned(
+            Ref::<_, [u8]>::new_slice_unaligned(&mut buf[..]).unwrap(),
+            16,
+        );
+        buf = [0xFFu8; 16];
+        test_new_helper_slice_unaligned(
+            Ref::<_, [u8]>::new_slice_unaligned_zeroed(&mut buf[..]).unwrap(),
+            16,
+        );
+
+        {
+            buf = [0u8; 16];
+            let (r, suffix) =
+                Ref::<_, [u8]>::new_slice_unaligned_from_prefix(&mut buf[..], 8).unwrap();
+            assert_eq!(suffix, [0; 8]);
+            test_new_helper_slice_unaligned(r, 8);
+        }
+        {
+            buf = [0xFFu8; 16];
+            let (r, suffix) =
+                Ref::<_, [u8]>::new_slice_unaligned_from_prefix_zeroed(&mut buf[..], 8).unwrap();
+            assert_eq!(suffix, [0xFF; 8]);
+            test_new_helper_slice_unaligned(r, 8);
+        }
+        {
+            buf = [0u8; 16];
+            let (prefix, r) =
+                Ref::<_, [u8]>::new_slice_unaligned_from_suffix(&mut buf[..], 8).unwrap();
+            assert_eq!(prefix, [0; 8]);
+            test_new_helper_slice_unaligned(r, 8);
+        }
+        {
+            buf = [0xFFu8; 16];
+            let (prefix, r) =
+                Ref::<_, [u8]>::new_slice_unaligned_from_suffix_zeroed(&mut buf[..], 8).unwrap();
+            assert_eq!(prefix, [0xFF; 8]);
+            test_new_helper_slice_unaligned(r, 8);
+        }
+    }
+
+    #[test]
+    fn test_new_oversized() {
+        // Test that a properly-aligned, overly-sized buffer works for
+        // `new_from_prefix` and `new_from_suffix`, and that they return the
+        // remainder and prefix of the slice respectively. Test that
+        // `xxx_zeroed` behaves the same, and zeroes the memory.
+
+        let mut buf = Align::<[u8; 16], AU64>::default();
+        {
+            // In a block so that `r` and `suffix` don't live too long. `buf.t`
+            // should be aligned to 8, so this should always succeed.
+            let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap();
+            assert_eq!(suffix.len(), 8);
+            test_new_helper(r);
+        }
+        {
+            buf.t = [0xFFu8; 16];
+            // `buf.t` should be aligned to 8, so this should always succeed.
+            let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap();
+            // Assert that the suffix wasn't zeroed.
+            assert_eq!(suffix, &[0xFFu8; 8]);
+            test_new_helper(r);
+        }
+        {
+            buf.set_default();
+            // `buf.t` should be aligned to 8, so this should always succeed.
+            let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap();
+            assert_eq!(prefix.len(), 8);
+            test_new_helper(r);
+        }
+        {
+            buf.t = [0xFFu8; 16];
+            // `buf.t` should be aligned to 8, so this should always succeed.
+            let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap();
+            // Assert that the prefix wasn't zeroed.
+            assert_eq!(prefix, &[0xFFu8; 8]);
+            test_new_helper(r);
+        }
+    }
+
+    #[test]
+    fn test_new_unaligned_oversized() {
+        // Test than an unaligned, overly-sized buffer works for
+        // `new_unaligned_from_prefix` and `new_unaligned_from_suffix`, and that
+        // they return the remainder and prefix of the slice respectively. Test
+        // that `xxx_zeroed` behaves the same, and zeroes the memory.
+
+        let mut buf = [0u8; 16];
+        {
+            // In a block so that `r` and `suffix` don't live too long.
+            let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap();
+            assert_eq!(suffix.len(), 8);
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0xFFu8; 16];
+            let (r, suffix) =
+                Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap();
+            // Assert that the suffix wasn't zeroed.
+            assert_eq!(suffix, &[0xFF; 8]);
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0u8; 16];
+            let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap();
+            assert_eq!(prefix.len(), 8);
+            test_new_helper_unaligned(r);
+        }
+        {
+            buf = [0xFFu8; 16];
+            let (prefix, r) =
+                Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap();
+            // Assert that the prefix wasn't zeroed.
+            assert_eq!(prefix, &[0xFF; 8]);
+            test_new_helper_unaligned(r);
+        }
+    }
+
+    #[test]
+    fn test_ref_from_mut_from() {
+        // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` success cases
+        // Exhaustive coverage for these methods is covered by the `Ref` tests above,
+        // which these helper methods defer to.
+
+        let mut buf =
+            Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
+
+        assert_eq!(
+            AU64::ref_from(&buf.t[8..]).unwrap().0.to_ne_bytes(),
+            [8, 9, 10, 11, 12, 13, 14, 15]
+        );
+        let suffix = AU64::mut_from(&mut buf.t[8..]).unwrap();
+        suffix.0 = 0x0101010101010101;
+        // The `[u8:9]` is a non-half size of the full buffer, which would catch
+        // `from_prefix` having the same implementation as `from_suffix` (issues #506, #511).
+        assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]);
+        let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap();
+        suffix.0 = 0x0202020202020202;
+        <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42;
+        assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]);
+        <[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30;
+        assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]);
+    }
+
+    #[test]
+    fn test_ref_from_mut_from_error() {
+        // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` error cases.
+
+        // Fail because the buffer is too large.
+        let mut buf = Align::<[u8; 16], AU64>::default();
+        // `buf.t` should be aligned to 8, so only the length check should fail.
+        assert!(AU64::ref_from(&buf.t[..]).is_none());
+        assert!(AU64::mut_from(&mut buf.t[..]).is_none());
+        assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
+        assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
+
+        // Fail because the buffer is too small.
+        let mut buf = Align::<[u8; 4], AU64>::default();
+        assert!(AU64::ref_from(&buf.t[..]).is_none());
+        assert!(AU64::mut_from(&mut buf.t[..]).is_none());
+        assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
+        assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
+        assert!(AU64::ref_from_prefix(&buf.t[..]).is_none());
+        assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_none());
+        assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
+        assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
+        assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_none());
+        assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_none());
+        assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_none());
+        assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_none());
+
+        // Fail because the alignment is insufficient.
+        let mut buf = Align::<[u8; 13], AU64>::default();
+        assert!(AU64::ref_from(&buf.t[1..]).is_none());
+        assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
+        assert!(AU64::ref_from(&buf.t[1..]).is_none());
+        assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
+        assert!(AU64::ref_from_prefix(&buf.t[1..]).is_none());
+        assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_none());
+        assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
+        assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
+    }
+
+    #[test]
+    #[allow(clippy::cognitive_complexity)]
+    fn test_new_error() {
+        // Fail because the buffer is too large.
+
+        // A buffer with an alignment of 8.
+        let mut buf = Align::<[u8; 16], AU64>::default();
+        // `buf.t` should be aligned to 8, so only the length check should fail.
+        assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none());
+
+        // Fail because the buffer is too small.
+
+        // A buffer with an alignment of 8.
+        let mut buf = Align::<[u8; 4], AU64>::default();
+        // `buf.t` should be aligned to 8, so only the length check should fail.
+        assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&buf.t[..]).is_none());
+        assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf.t[..]).is_none());
+
+        // Fail because the length is not a multiple of the element size.
+
+        let mut buf = Align::<[u8; 12], AU64>::default();
+        // `buf.t` has length 12, but element size is 8.
+        assert!(Ref::<_, [AU64]>::new_slice(&buf.t[..]).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned(&buf.t[..]).is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_zeroed(&mut buf.t[..]).is_none());
+
+        // Fail because the buffer is too short.
+        let mut buf = Align::<[u8; 12], AU64>::default();
+        // `buf.t` has length 12, but the element size is 8 (and we're expecting
+        // two of them).
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], 2).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 2).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], 2).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 2).is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], 2).is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed(&mut buf.t[..], 2)
+            .is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], 2).is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed(&mut buf.t[..], 2)
+            .is_none());
+
+        // Fail because the alignment is insufficient.
+
+        // A buffer with an alignment of 8. An odd buffer size is chosen so that
+        // the last byte of the buffer has odd alignment.
+        let mut buf = Align::<[u8; 13], AU64>::default();
+        // Slicing from 1, we get a buffer with size 12 (so the length check
+        // should succeed) but an alignment of only 1, which is insufficient.
+        assert!(Ref::<_, AU64>::new(&buf.t[1..]).is_none());
+        assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[1..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[1..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[1..]).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice(&buf.t[1..]).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[1..]).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[1..], 1).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[1..], 1).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[1..], 1).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[1..], 1).is_none());
+        // Slicing is unnecessary here because `new_from_suffix[_zeroed]` use
+        // the suffix of the slice, which has odd alignment.
+        assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none());
+        assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none());
+
+        // Fail due to arithmetic overflow.
+
+        let mut buf = Align::<[u8; 16], AU64>::default();
+        let unreasonable_len = usize::MAX / mem::size_of::<AU64>() + 1;
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], unreasonable_len).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], unreasonable_len)
+            .is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], unreasonable_len).is_none());
+        assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], unreasonable_len)
+            .is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], unreasonable_len)
+            .is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed(
+            &mut buf.t[..],
+            unreasonable_len
+        )
+        .is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], unreasonable_len)
+            .is_none());
+        assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed(
+            &mut buf.t[..],
+            unreasonable_len
+        )
+        .is_none());
+    }
+
+    // Tests for ensuring that, if a ZST is passed into a slice-like function,
+    // we always panic. Since these tests need to be separate per-function, and
+    // they tend to take up a lot of space, we generate them using a macro in a
+    // submodule instead. The submodule ensures that we can just re-use the name
+    // of the function under test for the name of the test itself.
+    mod test_zst_panics {
+        macro_rules! zst_test {
+            ($name:ident($($tt:tt)*), $constructor_in_panic_msg:tt) => {
+                #[test]
+                #[should_panic = concat!("Ref::", $constructor_in_panic_msg, " called on a zero-sized type")]
+                fn $name() {
+                    let mut buffer = [0u8];
+                    let r = $crate::Ref::<_, [()]>::$name(&mut buffer[..], $($tt)*);
+                    unreachable!("should have panicked, got {:?}", r);
+                }
+            }
+        }
+        zst_test!(new_slice(), "new_slice");
+        zst_test!(new_slice_zeroed(), "new_slice");
+        zst_test!(new_slice_from_prefix(1), "new_slice");
+        zst_test!(new_slice_from_prefix_zeroed(1), "new_slice");
+        zst_test!(new_slice_from_suffix(1), "new_slice");
+        zst_test!(new_slice_from_suffix_zeroed(1), "new_slice");
+        zst_test!(new_slice_unaligned(), "new_slice_unaligned");
+        zst_test!(new_slice_unaligned_zeroed(), "new_slice_unaligned");
+        zst_test!(new_slice_unaligned_from_prefix(1), "new_slice_unaligned");
+        zst_test!(new_slice_unaligned_from_prefix_zeroed(1), "new_slice_unaligned");
+        zst_test!(new_slice_unaligned_from_suffix(1), "new_slice_unaligned");
+        zst_test!(new_slice_unaligned_from_suffix_zeroed(1), "new_slice_unaligned");
+    }
+
+    #[test]
+    fn test_as_bytes_methods() {
+        /// Run a series of tests by calling `AsBytes` methods on `t`.
+        ///
+        /// `bytes` is the expected byte sequence returned from `t.as_bytes()`
+        /// before `t` has been modified. `post_mutation` is the expected
+        /// sequence returned from `t.as_bytes()` after `t.as_bytes_mut()[0]`
+        /// has had its bits flipped (by applying `^= 0xFF`).
+        ///
+        /// `N` is the size of `t` in bytes.
+        fn test<T: FromBytes + AsBytes + Debug + Eq + ?Sized, const N: usize>(
+            t: &mut T,
+            bytes: &[u8],
+            post_mutation: &T,
+        ) {
+            // Test that we can access the underlying bytes, and that we get the
+            // right bytes and the right number of bytes.
+            assert_eq!(t.as_bytes(), bytes);
+
+            // Test that changes to the underlying byte slices are reflected in
+            // the original object.
+            t.as_bytes_mut()[0] ^= 0xFF;
+            assert_eq!(t, post_mutation);
+            t.as_bytes_mut()[0] ^= 0xFF;
+
+            // `write_to` rejects slices that are too small or too large.
+            assert_eq!(t.write_to(&mut vec![0; N - 1][..]), None);
+            assert_eq!(t.write_to(&mut vec![0; N + 1][..]), None);
+
+            // `write_to` works as expected.
+            let mut bytes = [0; N];
+            assert_eq!(t.write_to(&mut bytes[..]), Some(()));
+            assert_eq!(bytes, t.as_bytes());
+
+            // `write_to_prefix` rejects slices that are too small.
+            assert_eq!(t.write_to_prefix(&mut vec![0; N - 1][..]), None);
+
+            // `write_to_prefix` works with exact-sized slices.
+            let mut bytes = [0; N];
+            assert_eq!(t.write_to_prefix(&mut bytes[..]), Some(()));
+            assert_eq!(bytes, t.as_bytes());
+
+            // `write_to_prefix` works with too-large slices, and any bytes past
+            // the prefix aren't modified.
+            let mut too_many_bytes = vec![0; N + 1];
+            too_many_bytes[N] = 123;
+            assert_eq!(t.write_to_prefix(&mut too_many_bytes[..]), Some(()));
+            assert_eq!(&too_many_bytes[..N], t.as_bytes());
+            assert_eq!(too_many_bytes[N], 123);
+
+            // `write_to_suffix` rejects slices that are too small.
+            assert_eq!(t.write_to_suffix(&mut vec![0; N - 1][..]), None);
+
+            // `write_to_suffix` works with exact-sized slices.
+            let mut bytes = [0; N];
+            assert_eq!(t.write_to_suffix(&mut bytes[..]), Some(()));
+            assert_eq!(bytes, t.as_bytes());
+
+            // `write_to_suffix` works with too-large slices, and any bytes
+            // before the suffix aren't modified.
+            let mut too_many_bytes = vec![0; N + 1];
+            too_many_bytes[0] = 123;
+            assert_eq!(t.write_to_suffix(&mut too_many_bytes[..]), Some(()));
+            assert_eq!(&too_many_bytes[1..], t.as_bytes());
+            assert_eq!(too_many_bytes[0], 123);
+        }
+
+        #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes)]
+        #[repr(C)]
+        struct Foo {
+            a: u32,
+            b: Wrapping<u32>,
+            c: Option<NonZeroU32>,
+        }
+
+        let expected_bytes: Vec<u8> = if cfg!(target_endian = "little") {
+            vec![1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]
+        } else {
+            vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0]
+        };
+        let post_mutation_expected_a =
+            if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 };
+        test::<_, 12>(
+            &mut Foo { a: 1, b: Wrapping(2), c: None },
+            expected_bytes.as_bytes(),
+            &Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None },
+        );
+        test::<_, 3>(
+            Unsized::from_mut_slice(&mut [1, 2, 3]),
+            &[1, 2, 3],
+            Unsized::from_mut_slice(&mut [0xFE, 2, 3]),
+        );
+    }
+
+    #[test]
+    fn test_array() {
+        #[derive(FromZeroes, FromBytes, AsBytes)]
+        #[repr(C)]
+        struct Foo {
+            a: [u16; 33],
+        }
+
+        let foo = Foo { a: [0xFFFF; 33] };
+        let expected = [0xFFu8; 66];
+        assert_eq!(foo.as_bytes(), &expected[..]);
+    }
+
+    #[test]
+    fn test_display_debug() {
+        let buf = Align::<[u8; 8], u64>::default();
+        let r = Ref::<_, u64>::new(&buf.t[..]).unwrap();
+        assert_eq!(format!("{}", r), "0");
+        assert_eq!(format!("{:?}", r), "Ref(0)");
+
+        let buf = Align::<[u8; 8], u64>::default();
+        let r = Ref::<_, [u64]>::new_slice(&buf.t[..]).unwrap();
+        assert_eq!(format!("{:?}", r), "Ref([0])");
+    }
+
+    #[test]
+    fn test_eq() {
+        let buf1 = 0_u64;
+        let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap();
+        let buf2 = 0_u64;
+        let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap();
+        assert_eq!(r1, r2);
+    }
+
+    #[test]
+    fn test_ne() {
+        let buf1 = 0_u64;
+        let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap();
+        let buf2 = 1_u64;
+        let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap();
+        assert_ne!(r1, r2);
+    }
+
+    #[test]
+    fn test_ord() {
+        let buf1 = 0_u64;
+        let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap();
+        let buf2 = 1_u64;
+        let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap();
+        assert!(r1 < r2);
+    }
+
+    #[test]
+    fn test_new_zeroed() {
+        assert!(!bool::new_zeroed());
+        assert_eq!(u64::new_zeroed(), 0);
+        // This test exists in order to exercise unsafe code, especially when
+        // running under Miri.
+        #[allow(clippy::unit_cmp)]
+        {
+            assert_eq!(<()>::new_zeroed(), ());
+        }
+    }
+
+    #[test]
+    fn test_transparent_packed_generic_struct() {
+        #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+        #[repr(transparent)]
+        #[allow(dead_code)] // for the unused fields
+        struct Foo<T> {
+            _t: T,
+            _phantom: PhantomData<()>,
+        }
+
+        assert_impl_all!(Foo<u32>: FromZeroes, FromBytes, AsBytes);
+        assert_impl_all!(Foo<u8>: Unaligned);
+
+        #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)]
+        #[repr(packed)]
+        #[allow(dead_code)] // for the unused fields
+        struct Bar<T, U> {
+            _t: T,
+            _u: U,
+        }
+
+        assert_impl_all!(Bar<u8, AU64>: FromZeroes, FromBytes, AsBytes, Unaligned);
+    }
+
+    #[test]
+    fn test_impls() {
+        use core::borrow::Borrow;
+
+        // A type that can supply test cases for testing
+        // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!`
+        // must implement this trait; that macro uses it to generate runtime
+        // tests for `TryFromBytes` impls.
+        //
+        // All `T: FromBytes` types are provided with a blanket impl. Other
+        // types must implement `TryFromBytesTestable` directly (ie using
+        // `impl_try_from_bytes_testable!`).
+        trait TryFromBytesTestable {
+            fn with_passing_test_cases<F: Fn(&Self)>(f: F);
+            fn with_failing_test_cases<F: Fn(&[u8])>(f: F);
+        }
+
+        impl<T: FromBytes> TryFromBytesTestable for T {
+            fn with_passing_test_cases<F: Fn(&Self)>(f: F) {
+                // Test with a zeroed value.
+                f(&Self::new_zeroed());
+
+                let ffs = {
+                    let mut t = Self::new_zeroed();
+                    let ptr: *mut T = &mut t;
+                    // SAFETY: `T: FromBytes`
+                    unsafe { ptr::write_bytes(ptr.cast::<u8>(), 0xFF, mem::size_of::<T>()) };
+                    t
+                };
+
+                // Test with a value initialized with 0xFF.
+                f(&ffs);
+            }
+
+            fn with_failing_test_cases<F: Fn(&[u8])>(_f: F) {}
+        }
+
+        // Implements `TryFromBytesTestable`.
+        macro_rules! impl_try_from_bytes_testable {
+            // Base case for recursion (when the list of types has run out).
+            (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {};
+            // Implements for type(s) with no type parameters.
+            ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
+                impl TryFromBytesTestable for $ty {
+                    impl_try_from_bytes_testable!(
+                        @methods     @success $($success_case),*
+                                 $(, @failure $($failure_case),*)?
+                    );
+                }
+                impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?);
+            };
+            // Implements for multiple types with no type parameters.
+            ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => {
+                $(
+                    impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*);
+                )*
+            };
+            // Implements only the methods; caller must invoke this from inside
+            // an impl block.
+            (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
+                fn with_passing_test_cases<F: Fn(&Self)>(_f: F) {
+                    $(
+                        _f($success_case.borrow());
+                    )*
+                }
+
+                fn with_failing_test_cases<F: Fn(&[u8])>(_f: F) {
+                    $($(
+                        let case = $failure_case.as_bytes();
+                        _f(case.as_bytes());
+                    )*)?
+                }
+            };
+        }
+
+        // Note that these impls are only for types which are not `FromBytes`.
+        // `FromBytes` types are covered by a preceding blanket impl.
+        impl_try_from_bytes_testable!(
+            bool => @success true, false,
+                    @failure 2u8, 3u8, 0xFFu8;
+            char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}',
+                    @failure 0xD800u32, 0xDFFFu32, 0x110000u32;
+            str  => @success "", "hello", "❤️🧡💛💚💙💜",
+                    @failure [0, 159, 146, 150];
+            [u8] => @success [], [0, 1, 2];
+            NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32,
+            NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128,
+            NonZeroUsize, NonZeroIsize
+                 => @success Self::new(1).unwrap(),
+                    // Doing this instead of `0` ensures that we always satisfy
+                    // the size and alignment requirements of `Self` (whereas
+                    // `0` may be any integer type with a different size or
+                    // alignment than some `NonZeroXxx` types).
+                    @failure Option::<Self>::None;
+            [bool]
+                => @success [true, false], [false, true],
+                    @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
+        );
+
+        // Asserts that `$ty` implements any `$trait` and doesn't implement any
+        // `!$trait`. Note that all `$trait`s must come before any `!$trait`s.
+        //
+        // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success
+        // and failure cases for `TryFromBytes::is_bit_valid`.
+        macro_rules! assert_impls {
+            ($ty:ty: TryFromBytes) => {
+                <$ty as TryFromBytesTestable>::with_passing_test_cases(|val| {
+                    let c = Ptr::from(val);
+                    // SAFETY:
+                    // - Since `val` is a normal reference, `c` is guranteed to
+                    //   be aligned, to point to a single allocation, and to
+                    //   have a size which doesn't overflow `isize`.
+                    // - Since `val` is a valid `$ty`, `c`'s referent satisfies
+                    //   the bit validity constraints of `is_bit_valid`, which
+                    //   are a superset of the bit validity constraints of
+                    //   `$ty`.
+                    let res = unsafe { <$ty as TryFromBytes>::is_bit_valid(c) };
+                    assert!(res, "{}::is_bit_valid({:?}): got false, expected true", stringify!($ty), val);
+
+                    // TODO(#5): In addition to testing `is_bit_valid`, test the
+                    // methods built on top of it. This would both allow us to
+                    // test their implementations and actually convert the bytes
+                    // to `$ty`, giving Miri a chance to catch if this is
+                    // unsound (ie, if our `is_bit_valid` impl is buggy).
+                    //
+                    // The following code was tried, but it doesn't work because
+                    // a) some types are not `AsBytes` and, b) some types are
+                    // not `Sized`.
+                    //
+                    //   let r = <$ty as TryFromBytes>::try_from_ref(val.as_bytes()).unwrap();
+                    //   assert_eq!(r, &val);
+                    //   let r = <$ty as TryFromBytes>::try_from_mut(val.as_bytes_mut()).unwrap();
+                    //   assert_eq!(r, &mut val);
+                    //   let v = <$ty as TryFromBytes>::try_read_from(val.as_bytes()).unwrap();
+                    //   assert_eq!(v, val);
+                });
+                #[allow(clippy::as_conversions)]
+                <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| {
+                    let res = <$ty as TryFromBytes>::try_from_ref(c);
+                    assert!(res.is_none(), "{}::is_bit_valid({:?}): got true, expected false", stringify!($ty), c);
+                });
+
+                #[allow(dead_code)]
+                const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); };
+            };
+            ($ty:ty: $trait:ident) => {
+                #[allow(dead_code)]
+                const _: () = { static_assertions::assert_impl_all!($ty: $trait); };
+            };
+            ($ty:ty: !$trait:ident) => {
+                #[allow(dead_code)]
+                const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); };
+            };
+            ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => {
+                $(
+                    assert_impls!($ty: $trait);
+                )*
+
+                $(
+                    assert_impls!($ty: !$negative_trait);
+                )*
+            };
+        }
+
+        // NOTE: The negative impl assertions here are not necessarily
+        // prescriptive. They merely serve as change detectors to make sure
+        // we're aware of what trait impls are getting added with a given
+        // change. Of course, some impls would be invalid (e.g., `bool:
+        // FromBytes`), and so this change detection is very important.
+
+        assert_impls!((): KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(u8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(i8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(u16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(i16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(u32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(i32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(u64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(i64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(u128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(i128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(usize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(isize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(f32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(f64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+
+        assert_impls!(bool: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes);
+        assert_impls!(char: KnownLayout, TryFromBytes, FromZeroes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(str: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes);
+
+        assert_impls!(NonZeroU8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes);
+        assert_impls!(NonZeroI8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes);
+        assert_impls!(NonZeroU16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroI16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroU32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroI32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroU64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroI64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroU128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroI128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroUsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+        assert_impls!(NonZeroIsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned);
+
+        assert_impls!(Option<NonZeroU8>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(Option<NonZeroI8>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(Option<NonZeroU16>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI16>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU32>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI32>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU64>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI64>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroU128>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroI128>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroUsize>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+        assert_impls!(Option<NonZeroIsize>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned);
+
+        // Implements none of the ZC traits.
+        struct NotZerocopy;
+
+        #[rustfmt::skip]
+        type FnManyArgs = fn(
+            NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+        ) -> (NotZerocopy, NotZerocopy);
+
+        // Allowed, because we're not actually using this type for FFI.
+        #[allow(improper_ctypes_definitions)]
+        #[rustfmt::skip]
+        type ECFnManyArgs = extern "C" fn(
+            NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
+        ) -> (NotZerocopy, NotZerocopy);
+
+        #[cfg(feature = "alloc")]
+        assert_impls!(Option<Box<UnsafeCell<NotZerocopy>>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<Box<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<&'static UnsafeCell<NotZerocopy>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<&'static [UnsafeCell<NotZerocopy>]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<&'static mut UnsafeCell<NotZerocopy>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<&'static mut [UnsafeCell<NotZerocopy>]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<NonNull<UnsafeCell<NotZerocopy>>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<NonNull<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<fn()>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<FnManyArgs>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<extern "C" fn()>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(Option<ECFnManyArgs>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+
+        assert_impls!(PhantomData<NotZerocopy>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(PhantomData<[u8]>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+
+        assert_impls!(ManuallyDrop<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
+        assert_impls!(ManuallyDrop<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
+        assert_impls!(ManuallyDrop<NotZerocopy>: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(ManuallyDrop<[NotZerocopy]>: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+
+        assert_impls!(MaybeUninit<u8>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, Unaligned, !AsBytes);
+        assert_impls!(MaybeUninit<NotZerocopy>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+
+        assert_impls!(Wrapping<u8>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+
+        assert_impls!(Unalign<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
+        assert_impls!(Unalign<NotZerocopy>: Unaligned, !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes);
+
+        assert_impls!([u8]: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
+        assert_impls!([bool]: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes);
+        assert_impls!([NotZerocopy]: !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!([u8; 0]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
+        assert_impls!([NotZerocopy; 0]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!([u8; 1]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
+        assert_impls!([NotZerocopy; 1]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+
+        assert_impls!(*const NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(*mut NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(*const [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(*mut [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(*const dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+        assert_impls!(*mut dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
+
+        #[cfg(feature = "simd")]
+        {
+            #[allow(unused_macros)]
+            macro_rules! test_simd_arch_mod {
+                ($arch:ident, $($typ:ident),*) => {
+                    {
+                        use core::arch::$arch::{$($typ),*};
+                        use crate::*;
+                        $( assert_impls!($typ: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); )*
+                    }
+                };
+            }
+            #[cfg(target_arch = "x86")]
+            test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
+
+            #[cfg(all(feature = "simd-nightly", target_arch = "x86"))]
+            test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i);
+
+            #[cfg(target_arch = "x86_64")]
+            test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
+
+            #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))]
+            test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i);
+
+            #[cfg(target_arch = "wasm32")]
+            test_simd_arch_mod!(wasm32, v128);
+
+            #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
+            test_simd_arch_mod!(
+                powerpc,
+                vector_bool_long,
+                vector_double,
+                vector_signed_long,
+                vector_unsigned_long
+            );
+
+            #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
+            test_simd_arch_mod!(
+                powerpc64,
+                vector_bool_long,
+                vector_double,
+                vector_signed_long,
+                vector_unsigned_long
+            );
+            #[cfg(target_arch = "aarch64")]
+            #[rustfmt::skip]
+            test_simd_arch_mod!(
+                aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
+                int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
+                int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
+                poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
+                poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
+                uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t,
+                uint64x1_t, uint64x2_t
+            );
+            #[cfg(all(feature = "simd-nightly", target_arch = "arm"))]
+            #[rustfmt::skip]
+            test_simd_arch_mod!(arm, int8x4_t, uint8x4_t);
+        }
+    }
+}
+
+#[cfg(kani)]
+mod proofs {
+    use super::*;
+
+    impl kani::Arbitrary for DstLayout {
+        fn any() -> Self {
+            let align: NonZeroUsize = kani::any();
+            let size_info: SizeInfo = kani::any();
+
+            kani::assume(align.is_power_of_two());
+            kani::assume(align < DstLayout::THEORETICAL_MAX_ALIGN);
+
+            // For testing purposes, we most care about instantiations of
+            // `DstLayout` that can correspond to actual Rust types. We use
+            // `Layout` to verify that our `DstLayout` satisfies the validity
+            // conditions of Rust layouts.
+            kani::assume(
+                match size_info {
+                    SizeInfo::Sized { _size } => Layout::from_size_align(_size, align.get()),
+                    SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => {
+                        // `SliceDst`` cannot encode an exact size, but we know
+                        // it is at least `_offset` bytes.
+                        Layout::from_size_align(_offset, align.get())
+                    }
+                }
+                .is_ok(),
+            );
+
+            Self { align: align, size_info: size_info }
+        }
+    }
+
+    impl kani::Arbitrary for SizeInfo {
+        fn any() -> Self {
+            let is_sized: bool = kani::any();
+
+            match is_sized {
+                true => {
+                    let size: usize = kani::any();
+
+                    kani::assume(size <= isize::MAX as _);
+
+                    SizeInfo::Sized { _size: size }
+                }
+                false => SizeInfo::SliceDst(kani::any()),
+            }
+        }
+    }
+
+    impl kani::Arbitrary for TrailingSliceLayout {
+        fn any() -> Self {
+            let elem_size: usize = kani::any();
+            let offset: usize = kani::any();
+
+            kani::assume(elem_size < isize::MAX as _);
+            kani::assume(offset < isize::MAX as _);
+
+            TrailingSliceLayout { _elem_size: elem_size, _offset: offset }
+        }
+    }
+
+    #[kani::proof]
+    fn prove_dst_layout_extend() {
+        use crate::util::{core_layout::padding_needed_for, max, min};
+
+        let base: DstLayout = kani::any();
+        let field: DstLayout = kani::any();
+        let packed: Option<NonZeroUsize> = kani::any();
+
+        if let Some(max_align) = packed {
+            kani::assume(max_align.is_power_of_two());
+            kani::assume(base.align <= max_align);
+        }
+
+        // The base can only be extended if it's sized.
+        kani::assume(matches!(base.size_info, SizeInfo::Sized { .. }));
+        let base_size = if let SizeInfo::Sized { _size: size } = base.size_info {
+            size
+        } else {
+            unreachable!();
+        };
+
+        // Under the above conditions, `DstLayout::extend` will not panic.
+        let composite = base.extend(field, packed);
+
+        // The field's alignment is clamped by `max_align` (i.e., the
+        // `packed` attribute, if any) [1].
+        //
+        // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
+        //
+        //   The alignments of each field, for the purpose of positioning
+        //   fields, is the smaller of the specified alignment and the
+        //   alignment of the field's type.
+        let field_align = min(field.align, packed.unwrap_or(DstLayout::THEORETICAL_MAX_ALIGN));
+
+        // The struct's alignment is the maximum of its previous alignment and
+        // `field_align`.
+        assert_eq!(composite.align, max(base.align, field_align));
+
+        // Compute the minimum amount of inter-field padding needed to
+        // satisfy the field's alignment, and offset of the trailing field.
+        // [1]
+        //
+        // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers:
+        //
+        //   Inter-field padding is guaranteed to be the minimum required in
+        //   order to satisfy each field's (possibly altered) alignment.
+        let padding = padding_needed_for(base_size, field_align);
+        let offset = base_size + padding;
+
+        // For testing purposes, we'll also construct `alloc::Layout`
+        // stand-ins for `DstLayout`, and show that `extend` behaves
+        // comparably on both types.
+        let base_analog = Layout::from_size_align(base_size, base.align.get()).unwrap();
+
+        match field.size_info {
+            SizeInfo::Sized { _size: field_size } => {
+                if let SizeInfo::Sized { _size: composite_size } = composite.size_info {
+                    // If the trailing field is sized, the resulting layout
+                    // will be sized. Its size will be the sum of the
+                    // preceeding layout, the size of the new field, and the
+                    // size of inter-field padding between the two.
+                    assert_eq!(composite_size, offset + field_size);
+
+                    let field_analog =
+                        Layout::from_size_align(field_size, field_align.get()).unwrap();
+
+                    if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog)
+                    {
+                        assert_eq!(actual_offset, offset);
+                        assert_eq!(actual_composite.size(), composite_size);
+                        assert_eq!(actual_composite.align(), composite.align.get());
+                    } else {
+                        // An error here reflects that composite of `base`
+                        // and `field` cannot correspond to a real Rust type
+                        // fragment, because such a fragment would violate
+                        // the basic invariants of a valid Rust layout. At
+                        // the time of writing, `DstLayout` is a little more
+                        // permissive than `Layout`, so we don't assert
+                        // anything in this branch (e.g., unreachability).
+                    }
+                } else {
+                    panic!("The composite of two sized layouts must be sized.")
+                }
+            }
+            SizeInfo::SliceDst(TrailingSliceLayout {
+                _offset: field_offset,
+                _elem_size: field_elem_size,
+            }) => {
+                if let SizeInfo::SliceDst(TrailingSliceLayout {
+                    _offset: composite_offset,
+                    _elem_size: composite_elem_size,
+                }) = composite.size_info
+                {
+                    // The offset of the trailing slice component is the sum
+                    // of the offset of the trailing field and the trailing
+                    // slice offset within that field.
+                    assert_eq!(composite_offset, offset + field_offset);
+                    // The elem size is unchanged.
+                    assert_eq!(composite_elem_size, field_elem_size);
+
+                    let field_analog =
+                        Layout::from_size_align(field_offset, field_align.get()).unwrap();
+
+                    if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog)
+                    {
+                        assert_eq!(actual_offset, offset);
+                        assert_eq!(actual_composite.size(), composite_offset);
+                        assert_eq!(actual_composite.align(), composite.align.get());
+                    } else {
+                        // An error here reflects that composite of `base`
+                        // and `field` cannot correspond to a real Rust type
+                        // fragment, because such a fragment would violate
+                        // the basic invariants of a valid Rust layout. At
+                        // the time of writing, `DstLayout` is a little more
+                        // permissive than `Layout`, so we don't assert
+                        // anything in this branch (e.g., unreachability).
+                    }
+                } else {
+                    panic!("The extension of a layout with a DST must result in a DST.")
+                }
+            }
+        }
+    }
+
+    #[kani::proof]
+    #[kani::should_panic]
+    fn prove_dst_layout_extend_dst_panics() {
+        let base: DstLayout = kani::any();
+        let field: DstLayout = kani::any();
+        let packed: Option<NonZeroUsize> = kani::any();
+
+        if let Some(max_align) = packed {
+            kani::assume(max_align.is_power_of_two());
+            kani::assume(base.align <= max_align);
+        }
+
+        kani::assume(matches!(base.size_info, SizeInfo::SliceDst(..)));
+
+        let _ = base.extend(field, packed);
+    }
+
+    #[kani::proof]
+    fn prove_dst_layout_pad_to_align() {
+        use crate::util::core_layout::padding_needed_for;
+
+        let layout: DstLayout = kani::any();
+
+        let padded: DstLayout = layout.pad_to_align();
+
+        // Calling `pad_to_align` does not alter the `DstLayout`'s alignment.
+        assert_eq!(padded.align, layout.align);
+
+        if let SizeInfo::Sized { _size: unpadded_size } = layout.size_info {
+            if let SizeInfo::Sized { _size: padded_size } = padded.size_info {
+                // If the layout is sized, it will remain sized after padding is
+                // added. Its sum will be its unpadded size and the size of the
+                // trailing padding needed to satisfy its alignment
+                // requirements.
+                let padding = padding_needed_for(unpadded_size, layout.align);
+                assert_eq!(padded_size, unpadded_size + padding);
+
+                // Prove that calling `DstLayout::pad_to_align` behaves
+                // identically to `Layout::pad_to_align`.
+                let layout_analog =
+                    Layout::from_size_align(unpadded_size, layout.align.get()).unwrap();
+                let padded_analog = layout_analog.pad_to_align();
+                assert_eq!(padded_analog.align(), layout.align.get());
+                assert_eq!(padded_analog.size(), padded_size);
+            } else {
+                panic!("The padding of a sized layout must result in a sized layout.")
+            }
+        } else {
+            // If the layout is a DST, padding cannot be statically added.
+            assert_eq!(padded.size_info, layout.size_info);
+        }
+    }
+}
diff --git a/extra_versions/crates/zerocopy/src/macro_util.rs b/extra_versions/crates/zerocopy/src/macro_util.rs
new file mode 100644
index 0000000..d2c61ca
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/macro_util.rs
@@ -0,0 +1,673 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Utilities used by macros and by `zerocopy-derive`.
+//!
+//! These are defined here `zerocopy` rather than in code generated by macros or
+//! by `zerocopy-derive` so that they can be compiled once rather than
+//! recompiled for every invocation (e.g., if they were defined in generated
+//! code, then deriving `AsBytes` and `FromBytes` on three different types would
+//! result in the code in question being emitted and compiled six different
+//! times).
+
+#![allow(missing_debug_implementations)]
+
+use core::{marker::PhantomData, mem::ManuallyDrop};
+
+// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
+// `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+use core::ptr::{self, NonNull};
+
+/// A compile-time check that should be one particular value.
+pub trait ShouldBe<const VALUE: bool> {}
+
+/// A struct for checking whether `T` contains padding.
+pub struct HasPadding<T: ?Sized, const VALUE: bool>(PhantomData<T>);
+
+impl<T: ?Sized, const VALUE: bool> ShouldBe<VALUE> for HasPadding<T, VALUE> {}
+
+/// A type whose size is equal to `align_of::<T>()`.
+#[repr(C)]
+pub struct AlignOf<T> {
+    // This field ensures that:
+    // - The size is always at least 1 (the minimum possible alignment).
+    // - If the alignment is greater than 1, Rust has to round up to the next
+    //   multiple of it in order to make sure that `Align`'s size is a multiple
+    //   of that alignment. Without this field, its size could be 0, which is a
+    //   valid multiple of any alignment.
+    _u: u8,
+    _a: [T; 0],
+}
+
+impl<T> AlignOf<T> {
+    #[inline(never)] // Make `missing_inline_in_public_items` happy.
+    pub fn into_t(self) -> T {
+        unreachable!()
+    }
+}
+
+/// A type whose size is equal to `max(align_of::<T>(), align_of::<U>())`.
+#[repr(C)]
+pub union MaxAlignsOf<T, U> {
+    _t: ManuallyDrop<AlignOf<T>>,
+    _u: ManuallyDrop<AlignOf<U>>,
+}
+
+impl<T, U> MaxAlignsOf<T, U> {
+    #[inline(never)] // Make `missing_inline_in_public_items` happy.
+    pub fn new(_t: T, _u: U) -> MaxAlignsOf<T, U> {
+        unreachable!()
+    }
+}
+
+const _64K: usize = 1 << 16;
+
+// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
+// `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+#[repr(C, align(65536))]
+struct Aligned64kAllocation([u8; _64K]);
+
+/// A pointer to an aligned allocation of size 2^16.
+///
+/// # Safety
+///
+/// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an
+/// allocation with size and alignment 2^16, and to have valid provenance.
+// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
+// `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = {
+    const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]);
+    let ptr: *const Aligned64kAllocation = REF;
+    let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K);
+    // SAFETY:
+    // - `ptr` is derived from a Rust reference, which is guaranteed to be
+    //   non-null.
+    // - `ptr` is derived from an `&Aligned64kAllocation`, which has size and
+    //   alignment `_64K` as promised. Its length is initialized to `_64K`,
+    //   which means that it refers to the entire allocation.
+    // - `ptr` is derived from a Rust reference, which is guaranteed to have
+    //   valid provenance.
+    //
+    // TODO(#429): Once `NonNull::new_unchecked` docs document that it preserves
+    // provenance, cite those docs.
+    // TODO: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65
+    #[allow(clippy::as_conversions)]
+    unsafe {
+        NonNull::new_unchecked(ptr as *mut _)
+    }
+};
+
+/// Computes the offset of the base of the field `$trailing_field_name` within
+/// the type `$ty`.
+///
+/// `trailing_field_offset!` produces code which is valid in a `const` context.
+// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
+// `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! trailing_field_offset {
+    ($ty:ty, $trailing_field_name:tt) => {{
+        let min_size = {
+            let zero_elems: *const [()] =
+                $crate::macro_util::core_reexport::ptr::slice_from_raw_parts(
+                    $crate::macro_util::core_reexport::ptr::NonNull::<()>::dangling()
+                        .as_ptr()
+                        .cast_const(),
+                    0,
+                );
+            // SAFETY:
+            // - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call.
+            // - Otherwise:
+            //   - If `$ty` is not a slice DST, this pointer conversion will
+            //     fail due to "mismatched vtable kinds", and compilation will
+            //     fail.
+            //   - If `$ty` is a slice DST, the safety requirement is that "the
+            //     length of the slice tail must be an initialized integer, and
+            //     the size of the entire value (dynamic tail length +
+            //     statically sized prefix) must fit in isize." The length is
+            //     initialized to 0 above, and Rust guarantees that no type's
+            //     minimum size may overflow `isize`. [1]
+            //
+            // [1] TODO(#429),
+            // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465#issuecomment-1782206516):
+            // Citation for this?
+            unsafe {
+                #[allow(clippy::as_conversions)]
+                $crate::macro_util::core_reexport::mem::size_of_val_raw(zero_elems as *const $ty)
+            }
+        };
+
+        assert!(min_size <= _64K);
+
+        #[allow(clippy::as_conversions)]
+        let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty;
+
+        // SAFETY:
+        // - Thanks to the preceding `assert!`, we know that the value with zero
+        //   elements fits in `_64K` bytes, and thus in the allocation addressed
+        //   by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is
+        //   guaranteed to be no larger than this size, so this field projection
+        //   is guaranteed to remain in-bounds of its allocation.
+        // - Because the minimum size is no larger than `_64K` bytes, and
+        //   because an object's size must always be a multiple of its alignment
+        //   [1], we know that `$ty`'s alignment is no larger than `_64K`. The
+        //   allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to
+        //   be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s
+        //   alignment.
+        //
+        //   Note that, as of [2], this requirement is technically unnecessary
+        //   for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway
+        //   until we bump our MSRV.
+        //
+        // [1] Per https://doc.rust-lang.org/reference/type-layout.html:
+        //
+        //   The size of a value is always a multiple of its alignment.
+        //
+        // [2] https://github.com/rust-lang/reference/pull/1387
+        let field = unsafe {
+            $crate::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name)
+        };
+        // SAFETY:
+        // - Both `ptr` and `field` are derived from the same allocated object.
+        // - By the preceding safety comment, `field` is in bounds of that
+        //   allocated object.
+        // - The distance, in bytes, between `ptr` and `field` is required to be
+        //   a multiple of the size of `u8`, which is trivially true because
+        //   `u8`'s size is 1.
+        // - The distance, in bytes, cannot overflow `isize`. This is guaranteed
+        //   because no allocated object can have a size larger than can fit in
+        //   `isize`. [1]
+        // - The distance being in-bounds cannot rely on wrapping around the
+        //   address space. This is guaranteed because the same is guaranteed of
+        //   allocated objects. [1]
+        //
+        // [1] TODO(#429), TODO(https://github.com/rust-lang/rust/pull/116675):
+        //     Once these are guaranteed in the Reference, cite it.
+        let offset = unsafe { field.cast::<u8>().offset_from(ptr.cast::<u8>()) };
+        // Guaranteed not to be lossy: `field` comes after `ptr`, so the offset
+        // from `ptr` to `field` is guaranteed to be positive.
+        assert!(offset >= 0);
+        Some(
+            #[allow(clippy::as_conversions)]
+            {
+                offset as usize
+            },
+        )
+    }};
+}
+
+/// Computes alignment of `$ty: ?Sized`.
+///
+/// `align_of!` produces code which is valid in a `const` context.
+// TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this
+// `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! align_of {
+    ($ty:ty) => {{
+        // SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is
+        // guaranteed [1] to begin with the single-byte layout for `_byte`,
+        // followed by the padding needed to align `_trailing`, then the layout
+        // for `_trailing`, and finally any trailing padding bytes needed to
+        // correctly-align the entire struct.
+        //
+        // This macro computes the alignment of `$ty` by counting the number of
+        // bytes preceeding `_trailing`. For instance, if the alignment of `$ty`
+        // is `1`, then no padding is required align `_trailing` and it will be
+        // located immediately after `_byte` at offset 1. If the alignment of
+        // `$ty` is 2, then a single padding byte is required before
+        // `_trailing`, and `_trailing` will be located at offset 2.
+
+        // This correspondence between offset and alignment holds for all valid
+        // Rust alignments, and we confirm this exhaustively (or, at least up to
+        // the maximum alignment supported by `trailing_field_offset!`) in
+        // `test_align_of_dst`.
+        //
+        // [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc
+
+        #[repr(C)]
+        struct OffsetOfTrailingIsAlignment {
+            _byte: u8,
+            _trailing: $ty,
+        }
+
+        trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing)
+    }};
+}
+
+/// Does the struct type `$t` have padding?
+///
+/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
+/// struct type, or else `struct_has_padding!`'s result may be meaningless.
+///
+/// Note that `struct_has_padding!`'s results are independent of `repr` since
+/// they only consider the size of the type and the sizes of the fields.
+/// Whatever the repr, the size of the type already takes into account any
+/// padding that the compiler has decided to add. Structs with well-defined
+/// representations (such as `repr(C)`) can use this macro to check for padding.
+/// Note that while this may yield some consistent value for some `repr(Rust)`
+/// structs, it is not guaranteed across platforms or compilations.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! struct_has_padding {
+    ($t:ty, $($ts:ty),*) => {
+        core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())*
+    };
+}
+
+/// Does the union type `$t` have padding?
+///
+/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
+/// union type, or else `union_has_padding!`'s result may be meaningless.
+///
+/// Note that `union_has_padding!`'s results are independent of `repr` since
+/// they only consider the size of the type and the sizes of the fields.
+/// Whatever the repr, the size of the type already takes into account any
+/// padding that the compiler has decided to add. Unions with well-defined
+/// representations (such as `repr(C)`) can use this macro to check for padding.
+/// Note that while this may yield some consistent value for some `repr(Rust)`
+/// unions, it is not guaranteed across platforms or compilations.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! union_has_padding {
+    ($t:ty, $($ts:ty),*) => {
+        false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
+    };
+}
+
+/// Does `t` have alignment greater than or equal to `u`?  If not, this macro
+/// produces a compile error. It must be invoked in a dead codepath. This is
+/// used in `transmute_ref!` and `transmute_mut!`.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! assert_align_gt_eq {
+    ($t:ident, $u: ident) => {{
+        // The comments here should be read in the context of this macro's
+        // invocations in `transmute_ref!` and `transmute_mut!`.
+        #[allow(clippy::missing_transmute_annotations)]
+        if false {
+            // The type wildcard in this bound is inferred to be `T` because
+            // `align_of.into_t()` is assigned to `t` (which has type `T`).
+            let align_of: $crate::macro_util::AlignOf<_> = unreachable!();
+            $t = align_of.into_t();
+            // `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because
+            // of the inferred types of `t` and `u`.
+            let mut max_aligns = $crate::macro_util::MaxAlignsOf::new($t, $u);
+
+            // This transmute will only compile successfully if
+            // `align_of::<T>() == max(align_of::<T>(), align_of::<U>())` - in
+            // other words, if `align_of::<T>() >= align_of::<U>()`.
+            //
+            // SAFETY: This code is never run.
+            max_aligns = unsafe { $crate::macro_util::core_reexport::mem::transmute(align_of) };
+        } else {
+            loop {}
+        }
+    }};
+}
+
+/// Do `t` and `u` have the same size?  If not, this macro produces a compile
+/// error. It must be invoked in a dead codepath. This is used in
+/// `transmute_ref!` and `transmute_mut!`.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! assert_size_eq {
+    ($t:ident, $u: ident) => {{
+        // The comments here should be read in the context of this macro's
+        // invocations in `transmute_ref!` and `transmute_mut!`.
+        if false {
+            // SAFETY: This code is never run.
+            $u = unsafe {
+                // Clippy: It's okay to transmute a type to itself.
+                #[allow(clippy::useless_transmute, clippy::missing_transmute_annotations)]
+                $crate::macro_util::core_reexport::mem::transmute($t)
+            };
+        } else {
+            loop {}
+        }
+    }};
+}
+
+/// Transmutes a reference of one type to a reference of another type.
+///
+/// # Safety
+///
+/// The caller must guarantee that:
+/// - `Src: AsBytes`
+/// - `Dst: FromBytes`
+/// - `size_of::<Src>() == size_of::<Dst>()`
+/// - `align_of::<Src>() >= align_of::<Dst>()`
+#[inline(always)]
+pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+    src: &'src Src,
+) -> &'dst Dst {
+    let src: *const Src = src;
+    let dst = src.cast::<Dst>();
+    // SAFETY:
+    // - We know that it is sound to view the target type of the input reference
+    //   (`Src`) as the target type of the output reference (`Dst`) because the
+    //   caller has guaranteed that `Src: AsBytes`, `Dst: FromBytes`, and
+    //   `size_of::<Src>() == size_of::<Dst>()`.
+    // - We know that there are no `UnsafeCell`s, and thus we don't have to
+    //   worry about `UnsafeCell` overlap, because `Src: AsBytes` and `Dst:
+    //   FromBytes` both forbid `UnsafeCell`s.
+    // - The caller has guaranteed that alignment is not increased.
+    // - We know that the returned lifetime will not outlive the input lifetime
+    //   thanks to the lifetime bounds on this function.
+    unsafe { &*dst }
+}
+
+/// Transmutes a mutable reference of one type to a mutable reference of another
+/// type.
+///
+/// # Safety
+///
+/// The caller must guarantee that:
+/// - `Src: FromBytes + AsBytes`
+/// - `Dst: FromBytes + AsBytes`
+/// - `size_of::<Src>() == size_of::<Dst>()`
+/// - `align_of::<Src>() >= align_of::<Dst>()`
+#[inline(always)]
+pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+    src: &'src mut Src,
+) -> &'dst mut Dst {
+    let src: *mut Src = src;
+    let dst = src.cast::<Dst>();
+    // SAFETY:
+    // - We know that it is sound to view the target type of the input reference
+    //   (`Src`) as the target type of the output reference (`Dst`) and
+    //   vice-versa because the caller has guaranteed that `Src: FromBytes +
+    //   AsBytes`, `Dst: FromBytes + AsBytes`, and `size_of::<Src>() ==
+    //   size_of::<Dst>()`.
+    // - We know that there are no `UnsafeCell`s, and thus we don't have to
+    //   worry about `UnsafeCell` overlap, because `Src: FromBytes + AsBytes`
+    //   and `Dst: FromBytes + AsBytes` forbid `UnsafeCell`s.
+    // - The caller has guaranteed that alignment is not increased.
+    // - We know that the returned lifetime will not outlive the input lifetime
+    //   thanks to the lifetime bounds on this function.
+    unsafe { &mut *dst }
+}
+
+// NOTE: We can't change this to a `pub use core as core_reexport` until [1] is
+// fixed or we update to a semver-breaking version (as of this writing, 0.8.0)
+// on the `main` branch.
+//
+// [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573
+pub mod core_reexport {
+    pub use core::*;
+
+    pub mod mem {
+        pub use core::mem::*;
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use core::mem;
+
+    use super::*;
+    use crate::util::testutil::*;
+
+    #[test]
+    fn test_align_of() {
+        macro_rules! test {
+            ($ty:ty) => {
+                assert_eq!(mem::size_of::<AlignOf<$ty>>(), mem::align_of::<$ty>());
+            };
+        }
+
+        test!(());
+        test!(u8);
+        test!(AU64);
+        test!([AU64; 2]);
+    }
+
+    #[test]
+    fn test_max_aligns_of() {
+        macro_rules! test {
+            ($t:ty, $u:ty) => {
+                assert_eq!(
+                    mem::size_of::<MaxAlignsOf<$t, $u>>(),
+                    core::cmp::max(mem::align_of::<$t>(), mem::align_of::<$u>())
+                );
+            };
+        }
+
+        test!(u8, u8);
+        test!(u8, AU64);
+        test!(AU64, u8);
+    }
+
+    #[test]
+    fn test_typed_align_check() {
+        // Test that the type-based alignment check used in
+        // `assert_align_gt_eq!` behaves as expected.
+
+        macro_rules! assert_t_align_gteq_u_align {
+            ($t:ty, $u:ty, $gteq:expr) => {
+                assert_eq!(
+                    mem::size_of::<MaxAlignsOf<$t, $u>>() == mem::size_of::<AlignOf<$t>>(),
+                    $gteq
+                );
+            };
+        }
+
+        assert_t_align_gteq_u_align!(u8, u8, true);
+        assert_t_align_gteq_u_align!(AU64, AU64, true);
+        assert_t_align_gteq_u_align!(AU64, u8, true);
+        assert_t_align_gteq_u_align!(u8, AU64, false);
+    }
+
+    // TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove
+    // this `cfg` when `size_of_val_raw` is stabilized.
+    #[allow(clippy::decimal_literal_representation)]
+    #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+    #[test]
+    fn test_trailing_field_offset() {
+        assert_eq!(mem::align_of::<Aligned64kAllocation>(), _64K);
+
+        macro_rules! test {
+            (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{
+                #[$cfg]
+                #[allow(dead_code)] // fields are never read
+                struct Test($($ts,)* $trailing_field_ty);
+                assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect);
+            }};
+            (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {
+                test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect);
+                test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect);
+            };
+            (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) };
+            (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) };
+        }
+
+        test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0));
+        test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0));
+        test!(#[repr(C)] #[repr(C, packed)] (u8; u8) => Some(1));
+        test!(#[repr(C)] (; AU64) => Some(0));
+        test!(#[repr(C)] (; [AU64]) => Some(0));
+        test!(#[repr(C)] (u8; AU64) => Some(8));
+        test!(#[repr(C)] (u8; [AU64]) => Some(8));
+        test!(#[repr(C)] (; Nested<u8, AU64>) => Some(0));
+        test!(#[repr(C)] (; Nested<u8, [AU64]>) => Some(0));
+        test!(#[repr(C)] (u8; Nested<u8, AU64>) => Some(8));
+        test!(#[repr(C)] (u8; Nested<u8, [AU64]>) => Some(8));
+
+        // Test that `packed(N)` limits the offset of the trailing field.
+        test!(#[repr(C, packed(        1))] (u8; elain::Align<        2>) => Some(        1));
+        test!(#[repr(C, packed(        2))] (u8; elain::Align<        4>) => Some(        2));
+        test!(#[repr(C, packed(        4))] (u8; elain::Align<        8>) => Some(        4));
+        test!(#[repr(C, packed(        8))] (u8; elain::Align<       16>) => Some(        8));
+        test!(#[repr(C, packed(       16))] (u8; elain::Align<       32>) => Some(       16));
+        test!(#[repr(C, packed(       32))] (u8; elain::Align<       64>) => Some(       32));
+        test!(#[repr(C, packed(       64))] (u8; elain::Align<      128>) => Some(       64));
+        test!(#[repr(C, packed(      128))] (u8; elain::Align<      256>) => Some(      128));
+        test!(#[repr(C, packed(      256))] (u8; elain::Align<      512>) => Some(      256));
+        test!(#[repr(C, packed(      512))] (u8; elain::Align<     1024>) => Some(      512));
+        test!(#[repr(C, packed(     1024))] (u8; elain::Align<     2048>) => Some(     1024));
+        test!(#[repr(C, packed(     2048))] (u8; elain::Align<     4096>) => Some(     2048));
+        test!(#[repr(C, packed(     4096))] (u8; elain::Align<     8192>) => Some(     4096));
+        test!(#[repr(C, packed(     8192))] (u8; elain::Align<    16384>) => Some(     8192));
+        test!(#[repr(C, packed(    16384))] (u8; elain::Align<    32768>) => Some(    16384));
+        test!(#[repr(C, packed(    32768))] (u8; elain::Align<    65536>) => Some(    32768));
+        test!(#[repr(C, packed(    65536))] (u8; elain::Align<   131072>) => Some(    65536));
+        /* Alignments above 65536 are not yet supported.
+        test!(#[repr(C, packed(   131072))] (u8; elain::Align<   262144>) => Some(   131072));
+        test!(#[repr(C, packed(   262144))] (u8; elain::Align<   524288>) => Some(   262144));
+        test!(#[repr(C, packed(   524288))] (u8; elain::Align<  1048576>) => Some(   524288));
+        test!(#[repr(C, packed(  1048576))] (u8; elain::Align<  2097152>) => Some(  1048576));
+        test!(#[repr(C, packed(  2097152))] (u8; elain::Align<  4194304>) => Some(  2097152));
+        test!(#[repr(C, packed(  4194304))] (u8; elain::Align<  8388608>) => Some(  4194304));
+        test!(#[repr(C, packed(  8388608))] (u8; elain::Align< 16777216>) => Some(  8388608));
+        test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216));
+        test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432));
+        test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864));
+        test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432));
+        test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728));
+        test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456));
+        */
+
+        // Test that `align(N)` does not limit the offset of the trailing field.
+        test!(#[repr(C, align(        1))] (u8; elain::Align<        2>) => Some(        2));
+        test!(#[repr(C, align(        2))] (u8; elain::Align<        4>) => Some(        4));
+        test!(#[repr(C, align(        4))] (u8; elain::Align<        8>) => Some(        8));
+        test!(#[repr(C, align(        8))] (u8; elain::Align<       16>) => Some(       16));
+        test!(#[repr(C, align(       16))] (u8; elain::Align<       32>) => Some(       32));
+        test!(#[repr(C, align(       32))] (u8; elain::Align<       64>) => Some(       64));
+        test!(#[repr(C, align(       64))] (u8; elain::Align<      128>) => Some(      128));
+        test!(#[repr(C, align(      128))] (u8; elain::Align<      256>) => Some(      256));
+        test!(#[repr(C, align(      256))] (u8; elain::Align<      512>) => Some(      512));
+        test!(#[repr(C, align(      512))] (u8; elain::Align<     1024>) => Some(     1024));
+        test!(#[repr(C, align(     1024))] (u8; elain::Align<     2048>) => Some(     2048));
+        test!(#[repr(C, align(     2048))] (u8; elain::Align<     4096>) => Some(     4096));
+        test!(#[repr(C, align(     4096))] (u8; elain::Align<     8192>) => Some(     8192));
+        test!(#[repr(C, align(     8192))] (u8; elain::Align<    16384>) => Some(    16384));
+        test!(#[repr(C, align(    16384))] (u8; elain::Align<    32768>) => Some(    32768));
+        test!(#[repr(C, align(    32768))] (u8; elain::Align<    65536>) => Some(    65536));
+        /* Alignments above 65536 are not yet supported.
+        test!(#[repr(C, align(    65536))] (u8; elain::Align<   131072>) => Some(   131072));
+        test!(#[repr(C, align(   131072))] (u8; elain::Align<   262144>) => Some(   262144));
+        test!(#[repr(C, align(   262144))] (u8; elain::Align<   524288>) => Some(   524288));
+        test!(#[repr(C, align(   524288))] (u8; elain::Align<  1048576>) => Some(  1048576));
+        test!(#[repr(C, align(  1048576))] (u8; elain::Align<  2097152>) => Some(  2097152));
+        test!(#[repr(C, align(  2097152))] (u8; elain::Align<  4194304>) => Some(  4194304));
+        test!(#[repr(C, align(  4194304))] (u8; elain::Align<  8388608>) => Some(  8388608));
+        test!(#[repr(C, align(  8388608))] (u8; elain::Align< 16777216>) => Some( 16777216));
+        test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432));
+        test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864));
+        test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432));
+        test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728));
+        test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456));
+        */
+    }
+
+    // TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove
+    // this `cfg` when `size_of_val_raw` is stabilized.
+    #[allow(clippy::decimal_literal_representation)]
+    #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+    #[test]
+    fn test_align_of_dst() {
+        // Test that `align_of!` correctly computes the alignment of DSTs.
+        assert_eq!(align_of!([elain::Align<1>]), Some(1));
+        assert_eq!(align_of!([elain::Align<2>]), Some(2));
+        assert_eq!(align_of!([elain::Align<4>]), Some(4));
+        assert_eq!(align_of!([elain::Align<8>]), Some(8));
+        assert_eq!(align_of!([elain::Align<16>]), Some(16));
+        assert_eq!(align_of!([elain::Align<32>]), Some(32));
+        assert_eq!(align_of!([elain::Align<64>]), Some(64));
+        assert_eq!(align_of!([elain::Align<128>]), Some(128));
+        assert_eq!(align_of!([elain::Align<256>]), Some(256));
+        assert_eq!(align_of!([elain::Align<512>]), Some(512));
+        assert_eq!(align_of!([elain::Align<1024>]), Some(1024));
+        assert_eq!(align_of!([elain::Align<2048>]), Some(2048));
+        assert_eq!(align_of!([elain::Align<4096>]), Some(4096));
+        assert_eq!(align_of!([elain::Align<8192>]), Some(8192));
+        assert_eq!(align_of!([elain::Align<16384>]), Some(16384));
+        assert_eq!(align_of!([elain::Align<32768>]), Some(32768));
+        assert_eq!(align_of!([elain::Align<65536>]), Some(65536));
+        /* Alignments above 65536 are not yet supported.
+        assert_eq!(align_of!([elain::Align<131072>]), Some(131072));
+        assert_eq!(align_of!([elain::Align<262144>]), Some(262144));
+        assert_eq!(align_of!([elain::Align<524288>]), Some(524288));
+        assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576));
+        assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152));
+        assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304));
+        assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608));
+        assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216));
+        assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
+        assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864));
+        assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
+        assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728));
+        assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456));
+        */
+    }
+
+    #[test]
+    fn test_struct_has_padding() {
+        // Test that, for each provided repr, `struct_has_padding!` reports the
+        // expected value.
+        macro_rules! test {
+            (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{
+                #[$cfg]
+                #[allow(dead_code)] // fields are never read
+                struct Test($($ts),*);
+                assert_eq!(struct_has_padding!(Test, $($ts),*), $expect);
+            }};
+            (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => {
+                test!(#[$cfg] ($($ts),*) => $expect);
+                test!($(#[$cfgs])* ($($ts),*) => $expect);
+            };
+        }
+
+        test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => false);
+        test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => false);
+        test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => false);
+        test!(#[repr(C)] #[repr(packed)] (u8, u8) => false);
+
+        test!(#[repr(C)] (u8, AU64) => true);
+        // Rust won't let you put `#[repr(packed)]` on a type which contains a
+        // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
+        // It's not ideal, but it definitely has align > 1 on /some/ of our CI
+        // targets, and this isn't a particularly complex macro we're testing
+        // anyway.
+        test!(#[repr(packed)] (u8, u64) => false);
+    }
+
+    #[test]
+    fn test_union_has_padding() {
+        // Test that, for each provided repr, `union_has_padding!` reports the
+        // expected value.
+        macro_rules! test {
+            (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{
+                #[$cfg]
+                #[allow(unused)] // fields are never read
+                union Test{ $($fs: $ts),* }
+                assert_eq!(union_has_padding!(Test, $($ts),*), $expect);
+            }};
+            (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => {
+                test!(#[$cfg] {$($fs: $ts),*} => $expect);
+                test!($(#[$cfgs])* {$($fs: $ts),*} => $expect);
+            };
+        }
+
+        test!(#[repr(C)] #[repr(packed)] {a: u8} => false);
+        test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => false);
+
+        // Rust won't let you put `#[repr(packed)]` on a type which contains a
+        // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
+        // It's not ideal, but it definitely has align > 1 on /some/ of our CI
+        // targets, and this isn't a particularly complex macro we're testing
+        // anyway.
+        test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => true);
+    }
+}
diff --git a/extra_versions/crates/zerocopy/src/macros.rs b/extra_versions/crates/zerocopy/src/macros.rs
new file mode 100644
index 0000000..a3d7996
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/macros.rs
@@ -0,0 +1,416 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+/// Documents multiple unsafe blocks with a single safety comment.
+///
+/// Invoked as:
+///
+/// ```rust,ignore
+/// safety_comment! {
+///     // Non-doc comments come first.
+///     /// SAFETY:
+///     /// Safety comment starts on its own line.
+///     macro_1!(args);
+///     macro_2! { args };
+///     /// SAFETY:
+///     /// Subsequent safety comments are allowed but not required.
+///     macro_3! { args };
+/// }
+/// ```
+///
+/// The macro invocations are emitted, each decorated with the following
+/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`.
+macro_rules! safety_comment {
+    (#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => {
+        #[allow(clippy::undocumented_unsafe_blocks, unused_attributes)]
+        const _: () = { $($(#[$attr])* $macro!$args;)* };
+    }
+}
+
+/// Unsafely implements trait(s) for a type.
+///
+/// # Safety
+///
+/// The trait impl must be sound.
+///
+/// When implementing `TryFromBytes`:
+/// - If no `is_bit_valid` impl is provided, then it must be valid for
+///   `is_bit_valid` to unconditionally return `true`. In other words, it must
+///   be the case that any initialized sequence of bytes constitutes a valid
+///   instance of `$ty`.
+/// - If an `is_bit_valid` impl is provided, then:
+///   - Regardless of whether the provided closure takes a `Ptr<$repr>` or
+///     `&$repr` argument, it must be the case that, given `t: *mut $ty` and
+///     `let r = t as *mut $repr`, `r` refers to an object of equal or lesser
+///     size than the object referred to by `t`.
+///   - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a,
+///     $ty>` which satisfies the preconditions of
+///     `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the
+///     memory referenced by that `Ptr` always contains a valid `$repr`.
+///   - The alignment of `$repr` is less than or equal to the alignment of
+///     `$ty`.
+///   - The impl of `is_bit_valid` must only return `true` for its argument
+///     `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`.
+macro_rules! unsafe_impl {
+    // Implement `$trait` for `$ty` with no bounds.
+    ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: &$repr:ty| $is_bit_valid:expr)?) => {
+        $(#[$attr])*
+        unsafe impl $trait for $ty {
+            unsafe_impl!(@method $trait $(; |$candidate: &$repr| $is_bit_valid)?);
+        }
+    };
+    // Implement all `$traits` for `$ty` with no bounds.
+    ($ty:ty: $($traits:ident),*) => {
+        $( unsafe_impl!($ty: $traits); )*
+    };
+    // This arm is identical to the following one, except it contains a
+    // preceding `const`. If we attempt to handle these with a single arm, there
+    // is an inherent ambiguity between `const` (the keyword) and `const` (the
+    // ident match for `$tyvar:ident`).
+    //
+    // To explain how this works, consider the following invocation:
+    //
+    //   unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>);
+    //
+    // In this invocation, here are the assignments to meta-variables:
+    //
+    //   |---------------|------------|
+    //   | Meta-variable | Assignment |
+    //   |---------------|------------|
+    //   | $constname    |  N         |
+    //   | $constty      |  usize     |
+    //   | $tyvar        |  T         |
+    //   | $optbound     |  Sized     |
+    //   | $bound        |  Copy      |
+    //   | $trait        |  Clone     |
+    //   | $ty           |  Foo<T>    |
+    //   |---------------|------------|
+    //
+    // The following arm has the same behavior with the exception of the lack of
+    // support for a leading `const` parameter.
+    (
+        $(#[$attr:meta])*
+        const $constname:ident : $constty:ident $(,)?
+        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
+    ) => {
+        unsafe_impl!(
+            @inner
+            $(#[$attr])*
+            @const $constname: $constty,
+            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
+            => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
+        );
+    };
+    (
+        $(#[$attr:meta])*
+        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
+    ) => {
+        unsafe_impl!(
+            @inner
+            $(#[$attr])*
+            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
+            => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
+        );
+    };
+    (
+        @inner
+        $(#[$attr:meta])*
+        $(@const $constname:ident : $constty:ident,)*
+        $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
+        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
+    ) => {
+        $(#[$attr])*
+        unsafe impl<$(const $constname: $constty,)* $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> $trait for $ty {
+            unsafe_impl!(@method $trait $(; |$candidate: $(&$ref_repr)? $(Ptr<$ptr_repr>)?| $is_bit_valid)?);
+        }
+    };
+
+    (@method TryFromBytes ; |$candidate:ident: &$repr:ty| $is_bit_valid:expr) => {
+        #[inline]
+        unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
+            // SAFETY:
+            // - The argument to `cast_unsized` is `|p| p as *mut _` as required
+            //   by that method's safety precondition.
+            // - The caller has promised that the cast results in an object of
+            //   equal or lesser size.
+            // - The caller has promised that `$repr`'s alignment is less than
+            //   or equal to `Self`'s alignment.
+            #[allow(clippy::as_conversions)]
+            let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
+            // SAFETY:
+            // - The caller has promised that the referenced memory region will
+            //   contain a valid `$repr` for `'a`.
+            // - The memory may not be referenced by any mutable references.
+            //   This is a precondition of `is_bit_valid`.
+            // - The memory may not be mutated even via `UnsafeCell`s. This is a
+            //   precondition of `is_bit_valid`.
+            // - There must not exist any references to the same memory region
+            //   which contain `UnsafeCell`s at byte ranges which are not
+            //   identical to the byte ranges at which `T` contains
+            //   `UnsafeCell`s. This is a precondition of `is_bit_valid`.
+            let $candidate: &$repr = unsafe { candidate.as_ref() };
+            $is_bit_valid
+        }
+    };
+    (@method TryFromBytes ; |$candidate:ident: Ptr<$repr:ty>| $is_bit_valid:expr) => {
+        #[inline]
+        unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
+            // SAFETY:
+            // - The argument to `cast_unsized` is `|p| p as *mut _` as required
+            //   by that method's safety precondition.
+            // - The caller has promised that the cast results in an object of
+            //   equal or lesser size.
+            // - The caller has promised that `$repr`'s alignment is less than
+            //   or equal to `Self`'s alignment.
+            #[allow(clippy::as_conversions)]
+            let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
+            $is_bit_valid
+        }
+    };
+    (@method TryFromBytes) => { #[inline(always)] unsafe fn is_bit_valid(_: Ptr<'_, Self>) -> bool { true } };
+    (@method $trait:ident) => {
+        #[allow(clippy::missing_inline_in_public_items)]
+        fn only_derive_is_allowed_to_implement_this_trait() {}
+    };
+    (@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => {
+        compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
+    };
+}
+
+/// Implements a trait for a type, bounding on each memeber of the power set of
+/// a set of type variables. This is useful for implementing traits for tuples
+/// or `fn` types.
+///
+/// The last argument is the name of a macro which will be called in every
+/// `impl` block, and is expected to expand to the name of the type for which to
+/// implement the trait.
+///
+/// For example, the invocation:
+/// ```ignore
+/// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
+/// ```
+/// ...expands to:
+/// ```ignore
+/// unsafe impl       Foo for type!()     { ... }
+/// unsafe impl<B>    Foo for type!(B)    { ... }
+/// unsafe impl<A, B> Foo for type!(A, B) { ... }
+/// ```
+macro_rules! unsafe_impl_for_power_set {
+    ($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
+        unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...));
+        unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...));
+    };
+    ($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
+        unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...));
+    };
+    (@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
+        unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) {
+            #[allow(clippy::missing_inline_in_public_items)]
+            fn only_derive_is_allowed_to_implement_this_trait() {}
+        }
+    };
+}
+
+/// Expands to an `Option<extern "C" fn>` type with the given argument types and
+/// return type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_extern_c_fn {
+    ($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
+}
+
+/// Expands to a `Option<fn>` type with the given argument types and return
+/// type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_fn {
+    ($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
+}
+
+/// Implements trait(s) for a type or verifies the given implementation by
+/// referencing an existing (derived) implementation.
+///
+/// This macro exists so that we can provide zerocopy-derive as an optional
+/// dependency and still get the benefit of using its derives to validate that
+/// our trait impls are sound.
+///
+/// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`,
+/// `impl_or_verify!` emits the provided trait impl. When compiling with either
+/// of those cfgs, it is expected that the type in question is deriving the
+/// traits instead. In this case, `impl_or_verify!` emits code which validates
+/// that the given trait impl is at least as restrictive as the the impl emitted
+/// by the custom derive. This has the effect of confirming that the impl which
+/// is emitted when the `derive` feature is disabled is actually sound (on the
+/// assumption that the impl emitted by the custom derive is sound).
+///
+/// The caller is still required to provide a safety comment (e.g. using the
+/// `safety_comment!` macro) . The reason for this restriction is that, while
+/// `impl_or_verify!` can guarantee that the provided impl is sound when it is
+/// compiled with the appropriate cfgs, there is no way to guarantee that it is
+/// ever compiled with those cfgs. In particular, it would be possible to
+/// accidentally place an `impl_or_verify!` call in a context that is only ever
+/// compiled when the `derive` feature is disabled. If that were to happen,
+/// there would be nothing to prevent an unsound trait impl from being emitted.
+/// Requiring a safety comment reduces the likelihood of emitting an unsound
+/// impl in this case, and also provides useful documentation for readers of the
+/// code.
+///
+/// ## Example
+///
+/// ```rust,ignore
+/// // Note that these derives are gated by `feature = "derive"`
+/// #[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
+/// #[repr(transparent)]
+/// struct Wrapper<T>(T);
+///
+/// safety_comment! {
+///     /// SAFETY:
+///     /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
+///     /// zerocopy trait if `T` implements that trait.
+///     impl_or_verify!(T: FromZeroes => FromZeroes for Wrapper<T>);
+///     impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
+///     impl_or_verify!(T: AsBytes => AsBytes for Wrapper<T>);
+///     impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
+/// }
+/// ```
+macro_rules! impl_or_verify {
+    // The following two match arms follow the same pattern as their
+    // counterparts in `unsafe_impl!`; see the documentation on those arms for
+    // more details.
+    (
+        const $constname:ident : $constty:ident $(,)?
+        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+        => $trait:ident for $ty:ty
+    ) => {
+        impl_or_verify!(@impl { unsafe_impl!(
+            const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
+        ); });
+        impl_or_verify!(@verify $trait, {
+            impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+        });
+    };
+    (
+        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+        => $trait:ident for $ty:ty
+    ) => {
+        impl_or_verify!(@impl { unsafe_impl!(
+            $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
+        ); });
+        impl_or_verify!(@verify $trait, {
+            impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+        });
+    };
+    (
+        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+        => $trait:ident for $ty:ty
+    ) => {
+        unsafe_impl!(
+            @inner
+            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
+            => $trait for $ty
+        );
+    };
+    (@impl $impl_block:tt) => {
+        #[cfg(not(any(feature = "derive", test)))]
+        const _: () = { $impl_block };
+    };
+    (@verify $trait:ident, $impl_block:tt) => {
+        #[cfg(any(feature = "derive", test))]
+        const _: () = {
+            trait Subtrait: $trait {}
+            $impl_block
+        };
+    };
+}
+
+/// Implements `KnownLayout` for a sized type.
+macro_rules! impl_known_layout {
+    ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
+        $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
+    };
+    ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
+        $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
+    };
+    ($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
+    (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
+        const _: () = {
+            use core::ptr::NonNull;
+
+            // SAFETY: Delegates safety to `DstLayout::for_type`.
+            unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
+                #[allow(clippy::missing_inline_in_public_items)]
+                fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
+
+                const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
+
+                // SAFETY: `.cast` preserves address and provenance.
+                //
+                // TODO(#429): Add documentation to `.cast` that promises that
+                // it preserves provenance.
+                #[inline(always)]
+                fn raw_from_ptr_len(bytes: NonNull<u8>, _elems: usize) -> NonNull<Self> {
+                    bytes.cast::<Self>()
+                }
+            }
+        };
+    };
+}
+
+/// Implements `KnownLayout` for a type in terms of the implementation of
+/// another type with the same representation.
+///
+/// # Safety
+///
+/// - `$ty` and `$repr` must have the same:
+///   - Fixed prefix size
+///   - Alignment
+///   - (For DSTs) trailing slice element size
+/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
+///   and this operation must preserve referent size (ie, `size_of_val_raw`).
+macro_rules! unsafe_impl_known_layout {
+    ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
+        const _: () = {
+            use core::ptr::NonNull;
+
+            unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
+                #[allow(clippy::missing_inline_in_public_items)]
+                fn only_derive_is_allowed_to_implement_this_trait() {}
+
+                const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
+
+                // SAFETY: All operations preserve address and provenance.
+                // Caller has promised that the `as` cast preserves size.
+                //
+                // TODO(#429): Add documentation to `NonNull::new_unchecked`
+                // that it preserves provenance.
+                #[inline(always)]
+                fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
+                    #[allow(clippy::as_conversions)]
+                    let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
+                    // SAFETY: `ptr` was converted from `bytes`, which is non-null.
+                    unsafe { NonNull::new_unchecked(ptr) }
+                }
+            }
+        };
+    };
+}
+
+/// Uses `align_of` to confirm that a type or set of types have alignment 1.
+///
+/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
+/// unsized types.
+macro_rules! assert_unaligned {
+    ($ty:ty) => {
+        // We only compile this assertion under `cfg(test)` to avoid taking an
+        // extra non-dev dependency (and making this crate more expensive to
+        // compile for our dependents).
+        #[cfg(test)]
+        static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1);
+    };
+    ($($ty:ty),*) => {
+        $(assert_unaligned!($ty);)*
+    };
+}
diff --git a/extra_versions/crates/zerocopy/src/post_monomorphization_compile_fail_tests.rs b/extra_versions/crates/zerocopy/src/post_monomorphization_compile_fail_tests.rs
new file mode 100644
index 0000000..32505b6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/post_monomorphization_compile_fail_tests.rs
@@ -0,0 +1,118 @@
+// Copyright 2018 The Fuchsia Authors
+//
+// Licensed under the 2-Clause BSD License <LICENSE-BSD or
+// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Code that should fail to compile during the post-monomorphization compiler
+//! pass.
+//!
+//! Due to [a limitation with the `trybuild` crate][trybuild-issue], we cannot
+//! use our UI testing framework to test compilation failures that are
+//! encountered after monomorphization has complated. This module has one item
+//! for each such test we would prefer to have as a UI test, with the code in
+//! question appearing as a rustdoc example which is marked with `compile_fail`.
+//! This has the effect of causing doctests to fail if any of these examples
+//! compile successfully.
+//!
+//! This is very much a hack and not a complete replacement for UI tests - most
+//! notably because this only provides a single "compile vs fail" bit of
+//! information, but does not allow us to depend upon the specific error that
+//! causes compilation to fail.
+//!
+//! [trybuild-issue]: https://github.com/dtolnay/trybuild/issues/241
+
+// Miri doesn't detect post-monimorphization failures as compile-time failures,
+// but instead as runtime failures.
+#![cfg(not(miri))]
+
+/// ```compile_fail
+/// use core::cell::{Ref, RefCell};
+///
+/// let refcell = RefCell::new([0u8, 1, 2, 3]);
+/// let core_ref = refcell.borrow();
+/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]);
+///
+/// // `zc_ref` now stores `core_ref` internally.
+/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref).unwrap();
+///
+/// // This causes `core_ref` to get dropped and synthesizes a Rust
+/// // reference to the memory `core_ref` was pointing at.
+/// let rust_ref = zc_ref.into_ref();
+///
+/// // UB!!! This mutates `rust_ref`'s referent while it's alive.
+/// *refcell.borrow_mut() = [0, 0, 0, 0];
+///
+/// println!("{}", rust_ref);
+/// ```
+#[allow(unused)]
+const REFCELL_REF_INTO_REF: () = ();
+
+/// ```compile_fail
+/// use core::cell::{RefCell, RefMut};
+///
+/// let refcell = RefCell::new([0u8, 1, 2, 3]);
+/// let core_ref_mut = refcell.borrow_mut();
+/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]);
+///
+/// // `zc_ref` now stores `core_ref_mut` internally.
+/// let zc_ref = zerocopy::Ref::<_, u32>::new(core_ref_mut).unwrap();
+///
+/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust
+/// // reference to the memory `core_ref` was pointing at.
+/// let rust_ref_mut = zc_ref.into_mut();
+///
+/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive.
+/// *refcell.borrow_mut() = [0, 0, 0, 0];
+///
+/// println!("{}", rust_ref_mut);
+/// ```
+#[allow(unused)]
+const REFCELL_REFMUT_INTO_MUT: () = ();
+
+/// ```compile_fail
+/// use core::cell::{Ref, RefCell};
+///
+/// let refcell = RefCell::new([0u8, 1, 2, 3]);
+/// let core_ref = refcell.borrow();
+/// let core_ref = Ref::map(core_ref, |bytes| &bytes[..]);
+///
+/// // `zc_ref` now stores `core_ref` internally.
+/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref).unwrap();
+///
+/// // This causes `core_ref` to get dropped and synthesizes a Rust
+/// // reference to the memory `core_ref` was pointing at.
+/// let rust_ref = zc_ref.into_slice();
+///
+/// // UB!!! This mutates `rust_ref`'s referent while it's alive.
+/// *refcell.borrow_mut() = [0, 0, 0, 0];
+///
+/// println!("{:?}", rust_ref);
+/// ```
+#[allow(unused)]
+const REFCELL_REFMUT_INTO_SLICE: () = ();
+
+/// ```compile_fail
+/// use core::cell::{RefCell, RefMut};
+///
+/// let refcell = RefCell::new([0u8, 1, 2, 3]);
+/// let core_ref_mut = refcell.borrow_mut();
+/// let core_ref_mut = RefMut::map(core_ref_mut, |bytes| &mut bytes[..]);
+///
+/// // `zc_ref` now stores `core_ref_mut` internally.
+/// let zc_ref = zerocopy::Ref::<_, [u16]>::new_slice(core_ref_mut).unwrap();
+///
+/// // This causes `core_ref_mut` to get dropped and synthesizes a Rust
+/// // reference to the memory `core_ref` was pointing at.
+/// let rust_ref_mut = zc_ref.into_mut_slice();
+///
+/// // UB!!! This mutates `rust_ref_mut`'s referent while it's alive.
+/// *refcell.borrow_mut() = [0, 0, 0, 0];
+///
+/// println!("{:?}", rust_ref_mut);
+/// ```
+#[allow(unused)]
+const REFCELL_REFMUT_INTO_MUT_SLICE: () = ();
diff --git a/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-APACHE b/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-APACHE
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-MIT b/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/third_party/rust/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/extra_versions/crates/zerocopy/src/third_party/rust/README.fuchsia b/extra_versions/crates/zerocopy/src/third_party/rust/README.fuchsia
new file mode 100644
index 0000000..e0a23dd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/third_party/rust/README.fuchsia
@@ -0,0 +1,7 @@
+Name: rust
+License File: LICENSE-APACHE
+License File: LICENSE-MIT
+Description:
+
+See https://github.com/google/zerocopy/pull/492 for an explanation of why this
+file exists.
diff --git a/extra_versions/crates/zerocopy/src/third_party/rust/layout.rs b/extra_versions/crates/zerocopy/src/third_party/rust/layout.rs
new file mode 100644
index 0000000..19ef7c6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/third_party/rust/layout.rs
@@ -0,0 +1,45 @@
+use core::num::NonZeroUsize;
+
+/// Returns the amount of padding we must insert after `len` bytes to ensure
+/// that the following address will satisfy `align` (measured in bytes).
+///
+/// e.g., if `len` is 9, then `padding_needed_for(len, 4)` returns 3, because
+/// that is the minimum number of bytes of padding required to get a 4-aligned
+/// address (assuming that the corresponding memory block starts at a 4-aligned
+/// address).
+///
+/// The return value of this function has no meaning if `align` is not a
+/// power-of-two.
+///
+/// # Panics
+///
+/// May panic if `align` is not a power of two.
+//
+// TODO(#419): Replace `len` with a witness type for region size.
+#[allow(unused)]
+#[inline(always)]
+pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
+    // Rounded up value is:
+    //   len_rounded_up = (len + align - 1) & !(align - 1);
+    // and then we return the padding difference: `len_rounded_up - len`.
+    //
+    // We use modular arithmetic throughout:
+    //
+    // 1. align is guaranteed to be > 0, so align - 1 is always
+    //    valid.
+    //
+    // 2. `len + align - 1` can overflow by at most `align - 1`,
+    //    so the &-mask with `!(align - 1)` will ensure that in the
+    //    case of overflow, `len_rounded_up` will itself be 0.
+    //    Thus the returned padding, when added to `len`, yields 0,
+    //    which trivially satisfies the alignment `align`.
+    //
+    // (Of course, attempts to allocate blocks of memory whose
+    // size and padding overflow in the above manner should cause
+    // the allocator to yield an error anyway.)
+
+    let align = align.get();
+    debug_assert!(align.is_power_of_two());
+    let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
+    len_rounded_up.wrapping_sub(len)
+}
diff --git a/extra_versions/crates/zerocopy/src/util.rs b/extra_versions/crates/zerocopy/src/util.rs
new file mode 100644
index 0000000..50cad1f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/util.rs
@@ -0,0 +1,810 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[path = "third_party/rust/layout.rs"]
+pub(crate) mod core_layout;
+
+use core::{mem, num::NonZeroUsize};
+
+pub(crate) mod ptr {
+    use core::{
+        fmt::{Debug, Formatter},
+        marker::PhantomData,
+        ptr::NonNull,
+    };
+
+    use crate::{util::AsAddress, KnownLayout, _CastType};
+
+    /// A raw pointer with more restrictions.
+    ///
+    /// `Ptr<T>` is similar to `NonNull<T>`, but it is more restrictive in the
+    /// following ways:
+    /// - It must derive from a valid allocation
+    /// - It must reference a byte range which is contained inside the
+    ///   allocation from which it derives
+    ///   - As a consequence, the byte range it references must have a size
+    ///     which does not overflow `isize`
+    /// - It must satisfy `T`'s alignment requirement
+    ///
+    /// Thanks to these restrictions, it is easier to prove the soundness of
+    /// some operations using `Ptr`s.
+    ///
+    /// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
+    ///
+    /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
+    pub struct Ptr<'a, T: 'a + ?Sized> {
+        // INVARIANTS:
+        // 1. `ptr` is derived from some valid Rust allocation, `A`
+        // 2. `ptr` has the same provenance as `A`
+        // 3. `ptr` addresses a byte range which is entirely contained in `A`
+        // 4. `ptr` addresses a byte range whose length fits in an `isize`
+        // 5. `ptr` addresses a byte range which does not wrap around the address
+        //     space
+        // 6. `ptr` is validly-aligned for `T`
+        // 7. `A` is guaranteed to live for at least `'a`
+        // 8. `T: 'a`
+        ptr: NonNull<T>,
+        _lifetime: PhantomData<&'a ()>,
+    }
+
+    impl<'a, T: ?Sized> Copy for Ptr<'a, T> {}
+    impl<'a, T: ?Sized> Clone for Ptr<'a, T> {
+        #[inline]
+        fn clone(&self) -> Self {
+            *self
+        }
+    }
+
+    impl<'a, T: ?Sized> Ptr<'a, T> {
+        /// Returns a shared reference to the value.
+        ///
+        /// # Safety
+        ///
+        /// For the duration of `'a`:
+        /// - The referenced memory must contain a validly-initialized `T` for
+        ///   the duration of `'a`.
+        /// - The referenced memory must not also be referenced by any mutable
+        ///   references.
+        /// - The referenced memory must not be mutated, even via an
+        ///   [`UnsafeCell`].
+        /// - There must not exist any references to the same memory region
+        ///   which contain `UnsafeCell`s at byte ranges which are not identical
+        ///   to the byte ranges at which `T` contains `UnsafeCell`s.
+        ///
+        /// [`UnsafeCell`]: core::cell::UnsafeCell
+        // TODO(#429): The safety requirements are likely overly-restrictive.
+        // Notably, mutation via `UnsafeCell`s is probably fine. Once the rules
+        // are more clearly defined, we should relax the safety requirements.
+        // For an example of why this is subtle, see:
+        // https://github.com/rust-lang/unsafe-code-guidelines/issues/463#issuecomment-1736771593
+        #[allow(unused)]
+        pub(crate) unsafe fn as_ref(&self) -> &'a T {
+            // SAFETY:
+            // - By invariant, `self.ptr` is properly-aligned for `T`.
+            // - By invariant, `self.ptr` is "dereferenceable" in that it points
+            //   to a single allocation.
+            // - By invariant, the allocation is live for `'a`.
+            // - The caller promises that no mutable references exist to this
+            //   region during `'a`.
+            // - The caller promises that `UnsafeCell`s match exactly.
+            // - The caller promises that no mutation will happen during `'a`,
+            //   even via `UnsafeCell`s.
+            // - The caller promises that the memory region contains a
+            //   validly-intialized `T`.
+            unsafe { self.ptr.as_ref() }
+        }
+
+        /// Casts to a different (unsized) target type.
+        ///
+        /// # Safety
+        ///
+        /// The caller promises that
+        /// - `cast(p)` is implemented exactly as follows: `|p: *mut T| p as
+        ///   *mut U`.
+        /// - The size of the object referenced by the resulting pointer is less
+        ///   than or equal to the size of the object referenced by `self`.
+        /// - The alignment of `U` is less than or equal to the alignment of
+        ///   `T`.
+        pub(crate) unsafe fn cast_unsized<U: 'a + ?Sized, F: FnOnce(*mut T) -> *mut U>(
+            self,
+            cast: F,
+        ) -> Ptr<'a, U> {
+            let ptr = cast(self.ptr.as_ptr());
+            // SAFETY: Caller promises that `cast` is just an `as` cast. We call
+            // `cast` on `self.ptr.as_ptr()`, which is non-null by construction.
+            let ptr = unsafe { NonNull::new_unchecked(ptr) };
+            // SAFETY:
+            // - By invariant, `self.ptr` is derived from some valid Rust
+            //   allocation, and since `ptr` is just `self.ptr as *mut U`, so is
+            //   `ptr`.
+            // - By invariant, `self.ptr` has the same provenance as `A`, and so
+            //   the same is true of `ptr`.
+            // - By invariant, `self.ptr` addresses a byte range which is
+            //   entirely contained in `A`, and so the same is true of `ptr`.
+            // - By invariant, `self.ptr` addresses a byte range whose length
+            //   fits in an `isize`, and so the same is true of `ptr`.
+            // - By invariant, `self.ptr` addresses a byte range which does not
+            //   wrap around the address space, and so the same is true of
+            //   `ptr`.
+            // - By invariant, `self.ptr` is validly-aligned for `T`. Since
+            //   `ptr` has the same address, and since the caller promises that
+            //   the alignment of `U` is less than or equal to the alignment of
+            //   `T`, `ptr` is validly-aligned for `U`.
+            // - By invariant, `A` is guaranteed to live for at least `'a`.
+            // - `U: 'a`
+            Ptr { ptr, _lifetime: PhantomData }
+        }
+    }
+
+    impl<'a> Ptr<'a, [u8]> {
+        /// Attempts to cast `self` to a `U` using the given cast type.
+        ///
+        /// Returns `None` if the resulting `U` would be invalidly-aligned or if
+        /// no `U` can fit in `self`. On success, returns a pointer to the
+        /// largest-possible `U` which fits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// The caller may assume that this implementation is correct, and may
+        /// rely on that assumption for the soundness of their code. In
+        /// particular, the caller may assume that, if `try_cast_into` returns
+        /// `Some((ptr, split_at))`, then:
+        /// - If this is a prefix cast, `ptr` refers to the byte range `[0,
+        ///   split_at)` in `self`.
+        /// - If this is a suffix cast, `ptr` refers to the byte range
+        ///   `[split_at, self.len())` in `self`.
+        ///
+        /// # Panics
+        ///
+        /// Panics if `U` is a DST whose trailing slice element is zero-sized.
+        pub(crate) fn try_cast_into<U: 'a + ?Sized + KnownLayout>(
+            &self,
+            cast_type: _CastType,
+        ) -> Option<(Ptr<'a, U>, usize)> {
+            // PANICS: By invariant, the byte range addressed by `self.ptr` does
+            // not wrap around the address space. This implies that the sum of
+            // the address (represented as a `usize`) and length do not overflow
+            // `usize`, as required by `validate_cast_and_convert_metadata`.
+            // Thus, this call to `validate_cast_and_convert_metadata` won't
+            // panic.
+            let (elems, split_at) = U::LAYOUT.validate_cast_and_convert_metadata(
+                AsAddress::addr(self.ptr.as_ptr()),
+                self.len(),
+                cast_type,
+            )?;
+            let offset = match cast_type {
+                _CastType::_Prefix => 0,
+                _CastType::_Suffix => split_at,
+            };
+
+            let ptr = self.ptr.cast::<u8>().as_ptr();
+            // SAFETY: `offset` is either `0` or `split_at`.
+            // `validate_cast_and_convert_metadata` promises that `split_at` is
+            // in the range `[0, self.len()]`. Thus, in both cases, `offset` is
+            // in `[0, self.len()]`. Thus:
+            // - The resulting pointer is in or one byte past the end of the
+            //   same byte range as `self.ptr`. Since, by invariant, `self.ptr`
+            //   addresses a byte range entirely contained within a single
+            //   allocation, the pointer resulting from this operation is within
+            //   or one byte past the end of that same allocation.
+            // - By invariant, `self.len() <= isize::MAX`. Since `offset <=
+            //   self.len()`, `offset <= isize::MAX`.
+            // - By invariant, `self.ptr` addresses a byte range which does not
+            //   wrap around the address space. This means that the base pointer
+            //   plus the `self.len()` does not overflow `usize`. Since `offset
+            //   <= self.len()`, this addition does not overflow `usize`.
+            let base = unsafe { ptr.add(offset) };
+            // SAFETY: Since `add` is not allowed to wrap around, the preceding line
+            // produces a pointer whose address is greater than or equal to that of
+            // `ptr`. Since `ptr` is a `NonNull`, `base` is also non-null.
+            let base = unsafe { NonNull::new_unchecked(base) };
+            let ptr = U::raw_from_ptr_len(base, elems);
+            // SAFETY:
+            // - By invariant, `self.ptr` is derived from some valid Rust
+            //   allocation, `A`, and has the same provenance as `A`. All
+            //   operations performed on `self.ptr` and values derived from it
+            //   in this method preserve provenance, so:
+            //   - `ptr` is derived from a valid Rust allocation, `A`.
+            //   - `ptr` has the same provenance as `A`.
+            // - `validate_cast_and_convert_metadata` promises that the object
+            //   described by `elems` and `split_at` lives at a byte range which
+            //   is a subset of the input byte range. Thus:
+            //   - Since, by invariant, `self.ptr` addresses a byte range
+            //     entirely contained in `A`, so does `ptr`.
+            //   - Since, by invariant, `self.ptr` addresses a range whose
+            //     length is not longer than `isize::MAX` bytes, so does `ptr`.
+            //   - Since, by invariant, `self.ptr` addresses a range which does
+            //     not wrap around the address space, so does `ptr`.
+            // - `validate_cast_and_convert_metadata` promises that the object
+            //   described by `split_at` is validly-aligned for `U`.
+            // - By invariant on `self`, `A` is guaranteed to live for at least
+            //   `'a`.
+            // - `U: 'a` by trait bound.
+            Some((Ptr { ptr, _lifetime: PhantomData }, split_at))
+        }
+
+        /// Attempts to cast `self` into a `U`, failing if all of the bytes of
+        /// `self` cannot be treated as a `U`.
+        ///
+        /// In particular, this method fails if `self` is not validly-aligned
+        /// for `U` or if `self`'s size is not a valid size for `U`.
+        ///
+        /// # Safety
+        ///
+        /// On success, the caller may assume that the returned pointer
+        /// references the same byte range as `self`.
+        #[allow(unused)]
+        #[inline(always)]
+        pub(crate) fn try_cast_into_no_leftover<U: 'a + ?Sized + KnownLayout>(
+            &self,
+        ) -> Option<Ptr<'a, U>> {
+            // TODO(#67): Remove this allow. See NonNulSlicelExt for more
+            // details.
+            #[allow(unstable_name_collisions)]
+            match self.try_cast_into(_CastType::_Prefix) {
+                Some((slf, split_at)) if split_at == self.len() => Some(slf),
+                Some(_) | None => None,
+            }
+        }
+    }
+
+    impl<'a, T> Ptr<'a, [T]> {
+        /// The number of slice elements referenced by `self`.
+        ///
+        /// # Safety
+        ///
+        /// Unsafe code my rely on `len` satisfying the above contract.
+        fn len(&self) -> usize {
+            #[allow(clippy::as_conversions)]
+            let slc = self.ptr.as_ptr() as *const [()];
+            // SAFETY:
+            // - `()` has alignment 1, so `slc` is trivially aligned.
+            // - `slc` was derived from a non-null pointer.
+            // - The size is 0 regardless of the length, so it is sound to
+            //   materialize a reference regardless of location.
+            // - By invariant, `self.ptr` has valid provenance.
+            let slc = unsafe { &*slc };
+            // This is correct because the preceding `as` cast preserves the
+            // number of slice elements. Per
+            // https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast:
+            //
+            //   For slice types like `[T]` and `[U]`, the raw pointer types
+            //   `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode
+            //   the number of elements in this slice. Casts between these raw
+            //   pointer types preserve the number of elements. Note that, as a
+            //   consequence, such casts do *not* necessarily preserve the size
+            //   of the pointer's referent (e.g., casting `*const [u16]` to
+            //   `*const [u8]` will result in a raw pointer which refers to an
+            //   object of half the size of the original). The same holds for
+            //   `str` and any compound type whose unsized tail is a slice type,
+            //   such as struct `Foo(i32, [u8])` or `(u64, Foo)`.
+            //
+            // TODO(#429),
+            // TODO(https://github.com/rust-lang/reference/pull/1417): Once this
+            // text is available on the Stable docs, cite those instead of the
+            // Nightly docs.
+            slc.len()
+        }
+
+        pub(crate) fn iter(&self) -> impl Iterator<Item = Ptr<'a, T>> {
+            // TODO(#429): Once `NonNull::cast` documents that it preserves
+            // provenance, cite those docs.
+            let base = self.ptr.cast::<T>().as_ptr();
+            (0..self.len()).map(move |i| {
+                // TODO(https://github.com/rust-lang/rust/issues/74265): Use
+                // `NonNull::get_unchecked_mut`.
+
+                // SAFETY: If the following conditions are not satisfied
+                // `pointer::cast` may induce Undefined Behavior [1]:
+                // > 1. Both the starting and resulting pointer must be either
+                // >    in bounds or one byte past the end of the same allocated
+                // >    object.
+                // > 2. The computed offset, in bytes, cannot overflow an
+                // >    `isize`.
+                // > 3. The offset being in bounds cannot rely on “wrapping
+                // >    around” the address space. That is, the
+                // >    infinite-precision sum must fit in a `usize`.
+                //
+                // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
+                //
+                // We satisfy all three of these conditions here:
+                // 1. `base` (by invariant on `self`) points to an allocated
+                //    object. By contract, `self.len()` accurately reflects the
+                //    number of elements in the slice. `i` is in bounds of
+                //   `c.len()` by construction, and so the result of this
+                //   addition cannot overflow past the end of the allocation
+                //   referred to by `c`.
+                // 2. By invariant on `Ptr`, `self` addresses a byte range whose
+                //    length fits in an `isize`. Since `elem` is contained in
+                //    `self`, the computed offset of `elem` must fit within
+                //    `isize.`
+                // 3. By invariant on `Ptr`, `self` addresses a byte range which
+                //    does not wrap around the address space. Since `elem` is
+                //    contained in `self`, the computed offset of `elem` must
+                //    wrap around the address space.
+                //
+                // TODO(#429): Once `pointer::add` documents that it preserves
+                // provenance, cite those docs.
+                let elem = unsafe { base.add(i) };
+
+                // SAFETY:
+                //  - `elem` must not be null. `base` is constructed from a
+                //    `NonNull` pointer, and the addition that produces `elem`
+                //    must not overflow or wrap around, so `elem >= base > 0`.
+                //
+                // TODO(#429): Once `NonNull::new_unchecked` documents that it
+                // preserves provenance, cite those docs.
+                let elem = unsafe { NonNull::new_unchecked(elem) };
+
+                // SAFETY: The safety invariants of `Ptr` (see definition) are
+                // satisfied:
+                // 1. `elem` is derived from a valid Rust allocation, because
+                //    `self` is derived from a valid Rust allocation, by
+                //    invariant on `Ptr`
+                // 2. `elem` has the same provenance as `self`, because it
+                //    derived from `self` using a series of
+                //    provenance-preserving operations
+                // 3. `elem` is entirely contained in the allocation of `self`
+                //    (see above)
+                // 4. `elem` addresses a byte range whose length fits in an
+                //    `isize` (see above)
+                // 5. `elem` addresses a byte range which does not wrap around
+                //    the address space (see above)
+                // 6. `elem` is validly-aligned for `T`. `self`, which
+                //    represents a `[T]` is validly aligned for `T`, and `elem`
+                //    is an element within that `[T]`
+                // 7. The allocation of `elem` is guaranteed to live for at
+                //    least `'a`, because `elem` is entirely contained in
+                //    `self`, which lives for at least `'a` by invariant on
+                //    `Ptr`.
+                // 8. `T: 'a`, because `elem` is an element within `[T]`, and
+                //    `[T]: 'a` by invariant on `Ptr`
+                Ptr { ptr: elem, _lifetime: PhantomData }
+            })
+        }
+    }
+
+    impl<'a, T: 'a + ?Sized> From<&'a T> for Ptr<'a, T> {
+        #[inline(always)]
+        fn from(t: &'a T) -> Ptr<'a, T> {
+            // SAFETY: `t` points to a valid Rust allocation, `A`, by
+            // construction. Thus:
+            // - `ptr` is derived from `A`
+            // - Since we use `NonNull::from`, which preserves provenance, `ptr`
+            //   has the same provenance as `A`
+            // - Since `NonNull::from` creates a pointer which addresses the
+            //   same bytes as `t`, `ptr` addresses a byte range entirely
+            //   contained in (in this case, identical to) `A`
+            // - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1]
+            // - Since `t: &T`, it addresses a byte range which does not wrap
+            //   around the address space [2]
+            // - Since it is constructed from a valid `&T`, `ptr` is
+            //   validly-aligned for `T`
+            // - Since `t: &'a T`, the allocation `A` is guaranteed to live for
+            //   at least `'a`
+            // - `T: 'a` by trait bound
+            //
+            // TODO(#429),
+            // TODO(https://github.com/rust-lang/rust/issues/116181): Once it's
+            // documented, reference the guarantee that `NonNull::from`
+            // preserves provenance.
+            //
+            // TODO(#429),
+            // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465):
+            // - [1] Where does the reference document that allocations fit in
+            //   `isize`?
+            // - [2] Where does the reference document that allocations don't
+            //   wrap around the address space?
+            Ptr { ptr: NonNull::from(t), _lifetime: PhantomData }
+        }
+    }
+
+    impl<'a, T: 'a + ?Sized> Debug for Ptr<'a, T> {
+        #[inline]
+        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+            self.ptr.fmt(f)
+        }
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use core::mem::{self, MaybeUninit};
+
+        use super::*;
+        use crate::{util::testutil::AU64, FromBytes};
+
+        #[test]
+        fn test_ptrtry_cast_into_soundness() {
+            // This test is designed so that if `Ptr::try_cast_into_xxx` are
+            // buggy, it will manifest as unsoundness that Miri can detect.
+
+            // - If `size_of::<T>() == 0`, `N == 4`
+            // - Else, `N == 4 * size_of::<T>()`
+            fn test<const N: usize, T: ?Sized + KnownLayout + FromBytes>() {
+                let mut bytes = [MaybeUninit::<u8>::uninit(); N];
+                let initialized = [MaybeUninit::new(0u8); N];
+                for start in 0..=bytes.len() {
+                    for end in start..=bytes.len() {
+                        // Set all bytes to uninitialized other than those in
+                        // the range we're going to pass to `try_cast_from`.
+                        // This allows Miri to detect out-of-bounds reads
+                        // because they read uninitialized memory. Without this,
+                        // some out-of-bounds reads would still be in-bounds of
+                        // `bytes`, and so might spuriously be accepted.
+                        bytes = [MaybeUninit::<u8>::uninit(); N];
+                        let bytes = &mut bytes[start..end];
+                        // Initialize only the byte range we're going to pass to
+                        // `try_cast_from`.
+                        bytes.copy_from_slice(&initialized[start..end]);
+
+                        let bytes = {
+                            let bytes: *const [MaybeUninit<u8>] = bytes;
+                            #[allow(clippy::as_conversions)]
+                            let bytes = bytes as *const [u8];
+                            // SAFETY: We just initialized these bytes to valid
+                            // `u8`s.
+                            unsafe { &*bytes }
+                        };
+
+                        /// # Safety
+                        ///
+                        /// - `slf` must reference a byte range which is
+                        ///   entirely initialized.
+                        /// - `slf` must reference a byte range which is only
+                        ///   referenced by shared references which do not
+                        ///   contain `UnsafeCell`s during its lifetime.
+                        unsafe fn validate_and_get_len<T: ?Sized + KnownLayout + FromBytes>(
+                            slf: Ptr<'_, T>,
+                        ) -> usize {
+                            // SAFETY:
+                            // - Since all bytes in `slf` are initialized and
+                            //   `T: FromBytes`, `slf` contains a valid `T`.
+                            // - The caller promises that the referenced memory
+                            //   is not also referenced by any mutable
+                            //   references.
+                            // - The caller promises that the referenced memory
+                            //   is not also referenced as a type which contains
+                            //   `UnsafeCell`s.
+                            let t = unsafe { slf.as_ref() };
+
+                            let bytes = {
+                                let len = mem::size_of_val(t);
+                                let t: *const T = t;
+                                // SAFETY:
+                                // - We know `t`'s bytes are all initialized
+                                //   because we just read it from `slf`, which
+                                //   points to an initialized range of bytes. If
+                                //   there's a bug and this doesn't hold, then
+                                //   that's exactly what we're hoping Miri will
+                                //   catch!
+                                // - Since `T: FromBytes`, `T` doesn't contain
+                                //   any `UnsafeCell`s, so it's okay for `t: T`
+                                //   and a `&[u8]` to the same memory to be
+                                //   alive concurrently.
+                                unsafe { core::slice::from_raw_parts(t.cast::<u8>(), len) }
+                            };
+
+                            // This assertion ensures that `t`'s bytes are read
+                            // and compared to another value, which in turn
+                            // ensures that Miri gets a chance to notice if any
+                            // of `t`'s bytes are uninitialized, which they
+                            // shouldn't be (see the comment above).
+                            assert_eq!(bytes, vec![0u8; bytes.len()]);
+
+                            mem::size_of_val(t)
+                        }
+
+                        for cast_type in [_CastType::_Prefix, _CastType::_Suffix] {
+                            if let Some((slf, split_at)) =
+                                Ptr::from(bytes).try_cast_into::<T>(cast_type)
+                            {
+                                // SAFETY: All bytes in `bytes` have been
+                                // initialized.
+                                let len = unsafe { validate_and_get_len(slf) };
+                                match cast_type {
+                                    _CastType::_Prefix => assert_eq!(split_at, len),
+                                    _CastType::_Suffix => assert_eq!(split_at, bytes.len() - len),
+                                }
+                            }
+                        }
+
+                        if let Some(slf) = Ptr::from(bytes).try_cast_into_no_leftover::<T>() {
+                            // SAFETY: All bytes in `bytes` have been
+                            // initialized.
+                            let len = unsafe { validate_and_get_len(slf) };
+                            assert_eq!(len, bytes.len());
+                        }
+                    }
+                }
+            }
+
+            macro_rules! test {
+            ($($ty:ty),*) => {
+                $({
+                    const S: usize = core::mem::size_of::<$ty>();
+                    const N: usize = if S == 0 { 4 } else { S * 4 };
+                    test::<N, $ty>();
+                    // We don't support casting into DSTs whose trailing slice
+                    // element is a ZST.
+                    if S > 0 {
+                        test::<N, [$ty]>();
+                    }
+                    // TODO: Test with a slice DST once we have any that
+                    // implement `KnownLayout + FromBytes`.
+                })*
+            };
+        }
+
+            test!(());
+            test!(u8, u16, u32, u64, u128, usize, AU64);
+            test!(i8, i16, i32, i64, i128, isize);
+            test!(f32, f64);
+        }
+    }
+}
+
+pub(crate) trait AsAddress {
+    fn addr(self) -> usize;
+}
+
+impl<'a, T: ?Sized> AsAddress for &'a T {
+    #[inline(always)]
+    fn addr(self) -> usize {
+        let ptr: *const T = self;
+        AsAddress::addr(ptr)
+    }
+}
+
+impl<'a, T: ?Sized> AsAddress for &'a mut T {
+    #[inline(always)]
+    fn addr(self) -> usize {
+        let ptr: *const T = self;
+        AsAddress::addr(ptr)
+    }
+}
+
+impl<T: ?Sized> AsAddress for *const T {
+    #[inline(always)]
+    fn addr(self) -> usize {
+        // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
+        // `.addr()` instead of `as usize` once it's stable, and get rid of this
+        // `allow`. Currently, `as usize` is the only way to accomplish this.
+        #[allow(clippy::as_conversions)]
+        #[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))]
+        return self.cast::<()>() as usize;
+    }
+}
+
+impl<T: ?Sized> AsAddress for *mut T {
+    #[inline(always)]
+    fn addr(self) -> usize {
+        let ptr: *const T = self;
+        AsAddress::addr(ptr)
+    }
+}
+
+/// Is `t` aligned to `mem::align_of::<U>()`?
+#[inline(always)]
+pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
+    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
+    // turn guarantees that this mod operation will not panic.
+    #[allow(clippy::arithmetic_side_effects)]
+    let remainder = t.addr() % mem::align_of::<U>();
+    remainder == 0
+}
+
+/// Round `n` down to the largest value `m` such that `m <= n` and `m % align ==
+/// 0`.
+///
+/// # Panics
+///
+/// May panic if `align` is not a power of two. Even if it doesn't panic in this
+/// case, it will produce nonsense results.
+#[inline(always)]
+pub(crate) const fn round_down_to_next_multiple_of_alignment(
+    n: usize,
+    align: NonZeroUsize,
+) -> usize {
+    let align = align.get();
+    debug_assert!(align.is_power_of_two());
+
+    // Subtraction can't underflow because `align.get() >= 1`.
+    #[allow(clippy::arithmetic_side_effects)]
+    let mask = !(align - 1);
+    n & mask
+}
+
+pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
+    if a.get() < b.get() {
+        b
+    } else {
+        a
+    }
+}
+
+pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
+    if a.get() > b.get() {
+        b
+    } else {
+        a
+    }
+}
+
+/// Since we support multiple versions of Rust, there are often features which
+/// have been stabilized in the most recent stable release which do not yet
+/// exist (stably) on our MSRV. This module provides polyfills for those
+/// features so that we can write more "modern" code, and just remove the
+/// polyfill once our MSRV supports the corresponding feature. Without this,
+/// we'd have to write worse/more verbose code and leave TODO comments sprinkled
+/// throughout the codebase to update to the new pattern once it's stabilized.
+///
+/// Each trait is imported as `_` at the crate root; each polyfill should "just
+/// work" at usage sites.
+pub(crate) mod polyfills {
+    use core::ptr::{self, NonNull};
+
+    // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
+    // MSRV is 1.70, when that function was stabilized.
+    //
+    // TODO(#67): Once our MSRV is 1.70, remove this.
+    #[allow(unused)]
+    pub(crate) trait NonNullExt<T> {
+        fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
+    }
+
+    #[allow(unused)]
+    impl<T> NonNullExt<T> for NonNull<T> {
+        #[inline(always)]
+        fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
+            let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
+            // SAFETY: `ptr` is converted from `data`, which is non-null.
+            unsafe { NonNull::new_unchecked(ptr) }
+        }
+    }
+}
+
+#[cfg(test)]
+pub(crate) mod testutil {
+    use core::fmt::{self, Display, Formatter};
+
+    use crate::*;
+
+    /// A `T` which is aligned to at least `align_of::<A>()`.
+    #[derive(Default)]
+    pub(crate) struct Align<T, A> {
+        pub(crate) t: T,
+        _a: [A; 0],
+    }
+
+    impl<T: Default, A> Align<T, A> {
+        pub(crate) fn set_default(&mut self) {
+            self.t = T::default();
+        }
+    }
+
+    impl<T, A> Align<T, A> {
+        pub(crate) const fn new(t: T) -> Align<T, A> {
+            Align { t, _a: [] }
+        }
+    }
+
+    // A `u64` with alignment 8.
+    //
+    // Though `u64` has alignment 8 on some platforms, it's not guaranteed.
+    // By contrast, `AU64` is guaranteed to have alignment 8.
+    #[derive(
+        KnownLayout,
+        FromZeroes,
+        FromBytes,
+        AsBytes,
+        Eq,
+        PartialEq,
+        Ord,
+        PartialOrd,
+        Default,
+        Debug,
+        Copy,
+        Clone,
+    )]
+    #[repr(C, align(8))]
+    pub(crate) struct AU64(pub(crate) u64);
+
+    impl AU64 {
+        // Converts this `AU64` to bytes using this platform's endianness.
+        pub(crate) fn to_bytes(self) -> [u8; 8] {
+            crate::transmute!(self)
+        }
+    }
+
+    impl Display for AU64 {
+        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+            Display::fmt(&self.0, f)
+        }
+    }
+
+    #[derive(
+        FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
+    )]
+    #[repr(C)]
+    pub(crate) struct Nested<T, U: ?Sized> {
+        _t: T,
+        _u: U,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_round_down_to_next_multiple_of_alignment() {
+        fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
+            let mul = n / align.get();
+            mul * align.get()
+        }
+
+        for align in [1, 2, 4, 8, 16] {
+            for n in 0..256 {
+                let align = NonZeroUsize::new(align).unwrap();
+                let want = alt_impl(n, align);
+                let got = round_down_to_next_multiple_of_alignment(n, align);
+                assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})");
+            }
+        }
+    }
+}
+
+#[cfg(kani)]
+mod proofs {
+    use super::*;
+
+    #[kani::proof]
+    fn prove_round_down_to_next_multiple_of_alignment() {
+        fn model_impl(n: usize, align: NonZeroUsize) -> usize {
+            assert!(align.get().is_power_of_two());
+            let mul = n / align.get();
+            mul * align.get()
+        }
+
+        let align: NonZeroUsize = kani::any();
+        kani::assume(align.get().is_power_of_two());
+        let n: usize = kani::any();
+
+        let expected = model_impl(n, align);
+        let actual = round_down_to_next_multiple_of_alignment(n, align);
+        assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})");
+    }
+
+    // Restricted to nightly since we use the unstable `usize::next_multiple_of`
+    // in our model implementation.
+    #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
+    #[kani::proof]
+    fn prove_padding_needed_for() {
+        fn model_impl(len: usize, align: NonZeroUsize) -> usize {
+            let padded = len.next_multiple_of(align.get());
+            let padding = padded - len;
+            padding
+        }
+
+        let align: NonZeroUsize = kani::any();
+        kani::assume(align.get().is_power_of_two());
+        let len: usize = kani::any();
+        // Constrain `len` to valid Rust lengths, since our model implementation
+        // isn't robust to overflow.
+        kani::assume(len <= isize::MAX as usize);
+        kani::assume(align.get() < 1 << 29);
+
+        let expected = model_impl(len, align);
+        let actual = core_layout::padding_needed_for(len, align);
+        assert_eq!(expected, actual, "padding_needed_for({len}, {align})");
+
+        let padded_len = actual + len;
+        assert_eq!(padded_len % align, 0);
+        assert!(padded_len / align >= len / align);
+    }
+}
diff --git a/extra_versions/crates/zerocopy/src/wrappers.rs b/extra_versions/crates/zerocopy/src/wrappers.rs
new file mode 100644
index 0000000..6532bb4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/src/wrappers.rs
@@ -0,0 +1,503 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use core::{
+    cmp::Ordering,
+    fmt::{self, Debug, Display, Formatter},
+    hash::Hash,
+    mem::{self, ManuallyDrop},
+    ops::{Deref, DerefMut},
+    ptr,
+};
+
+use super::*;
+
+/// A type with no alignment requirement.
+///
+/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign<T>`
+/// has the same size and bit validity as `T`, but not necessarily the same
+/// alignment [or ABI]. This is useful if a type with an alignment requirement
+/// needs to be read from a chunk of memory which provides no alignment
+/// guarantees.
+///
+/// Since `Unalign` has no alignment requirement, the inner `T` may not be
+/// properly aligned in memory. There are five ways to access the inner `T`:
+/// - by value, using [`get`] or [`into_inner`]
+/// - by reference inside of a callback, using [`update`]
+/// - fallibly by reference, using [`try_deref`] or [`try_deref_mut`]; these can
+///   fail if the `Unalign` does not satisfy `T`'s alignment requirement at
+///   runtime
+/// - unsafely by reference, using [`deref_unchecked`] or
+///   [`deref_mut_unchecked`]; it is the caller's responsibility to ensure that
+///   the `Unalign` satisfies `T`'s alignment requirement
+/// - (where `T: Unaligned`) infallibly by reference, using [`Deref::deref`] or
+///   [`DerefMut::deref_mut`]
+///
+/// [or ABI]: https://github.com/google/zerocopy/issues/164
+/// [`get`]: Unalign::get
+/// [`into_inner`]: Unalign::into_inner
+/// [`update`]: Unalign::update
+/// [`try_deref`]: Unalign::try_deref
+/// [`try_deref_mut`]: Unalign::try_deref_mut
+/// [`deref_unchecked`]: Unalign::deref_unchecked
+/// [`deref_mut_unchecked`]: Unalign::deref_mut_unchecked
+// NOTE: This type is sound to use with types that need to be dropped. The
+// reason is that the compiler-generated drop code automatically moves all
+// values to aligned memory slots before dropping them in-place. This is not
+// well-documented, but it's hinted at in places like [1] and [2]. However, this
+// also means that `T` must be `Sized`; unless something changes, we can never
+// support unsized `T`. [3]
+//
+// [1] https://github.com/rust-lang/rust/issues/54148#issuecomment-420529646
+// [2] https://github.com/google/zerocopy/pull/126#discussion_r1018512323
+// [3] https://github.com/google/zerocopy/issues/209
+#[allow(missing_debug_implementations)]
+#[derive(Default, Copy)]
+#[cfg_attr(
+    any(feature = "derive", test),
+    derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned)
+)]
+#[repr(C, packed)]
+pub struct Unalign<T>(T);
+
+#[cfg(not(any(feature = "derive", test)))]
+impl_known_layout!(T => Unalign<T>);
+
+safety_comment! {
+    /// SAFETY:
+    /// - `Unalign<T>` is `repr(packed)`, so it is unaligned regardless of the
+    ///   alignment of `T`, and so we don't require that `T: Unaligned`
+    /// - `Unalign<T>` has the same bit validity as `T`, and so it is
+    ///   `FromZeroes`, `FromBytes`, or `AsBytes` exactly when `T` is as well.
+    impl_or_verify!(T => Unaligned for Unalign<T>);
+    impl_or_verify!(T: FromZeroes => FromZeroes for Unalign<T>);
+    impl_or_verify!(T: FromBytes => FromBytes for Unalign<T>);
+    impl_or_verify!(T: AsBytes => AsBytes for Unalign<T>);
+}
+
+// Note that `Unalign: Clone` only if `T: Copy`. Since the inner `T` may not be
+// aligned, there's no way to safely call `T::clone`, and so a `T: Clone` bound
+// is not sufficient to implement `Clone` for `Unalign`.
+impl<T: Copy> Clone for Unalign<T> {
+    #[inline(always)]
+    fn clone(&self) -> Unalign<T> {
+        *self
+    }
+}
+
+impl<T> Unalign<T> {
+    /// Constructs a new `Unalign`.
+    #[inline(always)]
+    pub const fn new(val: T) -> Unalign<T> {
+        Unalign(val)
+    }
+
+    /// Consumes `self`, returning the inner `T`.
+    #[inline(always)]
+    pub const fn into_inner(self) -> T {
+        // Use this instead of `mem::transmute` since the latter can't tell
+        // that `Unalign<T>` and `T` have the same size.
+        #[repr(C)]
+        union Transmute<T> {
+            u: ManuallyDrop<Unalign<T>>,
+            t: ManuallyDrop<T>,
+        }
+
+        // SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same
+        // layout as `T`. `ManuallyDrop<U>` is guaranteed to have the same
+        // layout as `U`, and so `ManuallyDrop<Unalign<T>>` has the same layout
+        // as `ManuallyDrop<T>`. Since `Transmute<T>` is `#[repr(C)]`, its `t`
+        // and `u` fields both start at the same offset (namely, 0) within the
+        // union.
+        //
+        // We do this instead of just destructuring in order to prevent
+        // `Unalign`'s `Drop::drop` from being run, since dropping is not
+        // supported in `const fn`s.
+        //
+        // TODO(https://github.com/rust-lang/rust/issues/73255): Destructure
+        // instead of using unsafe.
+        unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) }
+    }
+
+    /// Attempts to return a reference to the wrapped `T`, failing if `self` is
+    /// not properly aligned.
+    ///
+    /// If `self` does not satisfy `mem::align_of::<T>()`, then it is unsound to
+    /// return a reference to the wrapped `T`, and `try_deref` returns `None`.
+    ///
+    /// If `T: Unaligned`, then `Unalign<T>` implements [`Deref`], and callers
+    /// may prefer [`Deref::deref`], which is infallible.
+    #[inline(always)]
+    pub fn try_deref(&self) -> Option<&T> {
+        if !util::aligned_to::<_, T>(self) {
+            return None;
+        }
+
+        // SAFETY: `deref_unchecked`'s safety requirement is that `self` is
+        // aligned to `align_of::<T>()`, which we just checked.
+        unsafe { Some(self.deref_unchecked()) }
+    }
+
+    /// Attempts to return a mutable reference to the wrapped `T`, failing if
+    /// `self` is not properly aligned.
+    ///
+    /// If `self` does not satisfy `mem::align_of::<T>()`, then it is unsound to
+    /// return a reference to the wrapped `T`, and `try_deref_mut` returns
+    /// `None`.
+    ///
+    /// If `T: Unaligned`, then `Unalign<T>` implements [`DerefMut`], and
+    /// callers may prefer [`DerefMut::deref_mut`], which is infallible.
+    #[inline(always)]
+    pub fn try_deref_mut(&mut self) -> Option<&mut T> {
+        if !util::aligned_to::<_, T>(&*self) {
+            return None;
+        }
+
+        // SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is
+        // aligned to `align_of::<T>()`, which we just checked.
+        unsafe { Some(self.deref_mut_unchecked()) }
+    }
+
+    /// Returns a reference to the wrapped `T` without checking alignment.
+    ///
+    /// If `T: Unaligned`, then `Unalign<T>` implements[ `Deref`], and callers
+    /// may prefer [`Deref::deref`], which is safe.
+    ///
+    /// # Safety
+    ///
+    /// If `self` does not satisfy `mem::align_of::<T>()`, then
+    /// `self.deref_unchecked()` may cause undefined behavior.
+    #[inline(always)]
+    pub const unsafe fn deref_unchecked(&self) -> &T {
+        // SAFETY: `Unalign<T>` is `repr(transparent)`, so there is a valid `T`
+        // at the same memory location as `self`. It has no alignment guarantee,
+        // but the caller has promised that `self` is properly aligned, so we
+        // know that it is sound to create a reference to `T` at this memory
+        // location.
+        //
+        // We use `mem::transmute` instead of `&*self.get_ptr()` because
+        // dereferencing pointers is not stable in `const` on our current MSRV
+        // (1.56 as of this writing).
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Returns a mutable reference to the wrapped `T` without checking
+    /// alignment.
+    ///
+    /// If `T: Unaligned`, then `Unalign<T>` implements[ `DerefMut`], and
+    /// callers may prefer [`DerefMut::deref_mut`], which is safe.
+    ///
+    /// # Safety
+    ///
+    /// If `self` does not satisfy `mem::align_of::<T>()`, then
+    /// `self.deref_mut_unchecked()` may cause undefined behavior.
+    #[inline(always)]
+    pub unsafe fn deref_mut_unchecked(&mut self) -> &mut T {
+        // SAFETY: `self.get_mut_ptr()` returns a raw pointer to a valid `T` at
+        // the same memory location as `self`. It has no alignment guarantee,
+        // but the caller has promised that `self` is properly aligned, so we
+        // know that the pointer itself is aligned, and thus that it is sound to
+        // create a reference to a `T` at this memory location.
+        unsafe { &mut *self.get_mut_ptr() }
+    }
+
+    /// Gets an unaligned raw pointer to the inner `T`.
+    ///
+    /// # Safety
+    ///
+    /// The returned raw pointer is not necessarily aligned to
+    /// `align_of::<T>()`. Most functions which operate on raw pointers require
+    /// those pointers to be aligned, so calling those functions with the result
+    /// of `get_ptr` will be undefined behavior if alignment is not guaranteed
+    /// using some out-of-band mechanism. In general, the only functions which
+    /// are safe to call with this pointer are those which are explicitly
+    /// documented as being sound to use with an unaligned pointer, such as
+    /// [`read_unaligned`].
+    ///
+    /// [`read_unaligned`]: core::ptr::read_unaligned
+    #[inline(always)]
+    pub const fn get_ptr(&self) -> *const T {
+        ptr::addr_of!(self.0)
+    }
+
+    /// Gets an unaligned mutable raw pointer to the inner `T`.
+    ///
+    /// # Safety
+    ///
+    /// The returned raw pointer is not necessarily aligned to
+    /// `align_of::<T>()`. Most functions which operate on raw pointers require
+    /// those pointers to be aligned, so calling those functions with the result
+    /// of `get_ptr` will be undefined behavior if alignment is not guaranteed
+    /// using some out-of-band mechanism. In general, the only functions which
+    /// are safe to call with this pointer are those which are explicitly
+    /// documented as being sound to use with an unaligned pointer, such as
+    /// [`read_unaligned`].
+    ///
+    /// [`read_unaligned`]: core::ptr::read_unaligned
+    // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
+    #[inline(always)]
+    pub fn get_mut_ptr(&mut self) -> *mut T {
+        ptr::addr_of_mut!(self.0)
+    }
+
+    /// Sets the inner `T`, dropping the previous value.
+    // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
+    #[inline(always)]
+    pub fn set(&mut self, t: T) {
+        *self = Unalign::new(t);
+    }
+
+    /// Updates the inner `T` by calling a function on it.
+    ///
+    /// If [`T: Unaligned`], then `Unalign<T>` implements [`DerefMut`], and that
+    /// impl should be preferred over this method when performing updates, as it
+    /// will usually be faster and more ergonomic.
+    ///
+    /// For large types, this method may be expensive, as it requires copying
+    /// `2 * size_of::<T>()` bytes. \[1\]
+    ///
+    /// \[1\] Since the inner `T` may not be aligned, it would not be sound to
+    /// invoke `f` on it directly. Instead, `update` moves it into a
+    /// properly-aligned location in the local stack frame, calls `f` on it, and
+    /// then moves it back to its original location in `self`.
+    ///
+    /// [`T: Unaligned`]: Unaligned
+    #[inline]
+    pub fn update<O, F: FnOnce(&mut T) -> O>(&mut self, f: F) -> O {
+        // On drop, this moves `copy` out of itself and uses `ptr::write` to
+        // overwrite `slf`.
+        struct WriteBackOnDrop<T> {
+            copy: ManuallyDrop<T>,
+            slf: *mut Unalign<T>,
+        }
+
+        impl<T> Drop for WriteBackOnDrop<T> {
+            fn drop(&mut self) {
+                // SAFETY: We never use `copy` again as required by
+                // `ManuallyDrop::take`.
+                let copy = unsafe { ManuallyDrop::take(&mut self.copy) };
+                // SAFETY: `slf` is the raw pointer value of `self`. We know it
+                // is valid for writes and properly aligned because `self` is a
+                // mutable reference, which guarantees both of these properties.
+                unsafe { ptr::write(self.slf, Unalign::new(copy)) };
+            }
+        }
+
+        // SAFETY: We know that `self` is valid for reads, properly aligned, and
+        // points to an initialized `Unalign<T>` because it is a mutable
+        // reference, which guarantees all of these properties.
+        //
+        // Since `T: !Copy`, it would be unsound in the general case to allow
+        // both the original `Unalign<T>` and the copy to be used by safe code.
+        // We guarantee that the copy is used to overwrite the original in the
+        // `Drop::drop` impl of `WriteBackOnDrop`. So long as this `drop` is
+        // called before any other safe code executes, soundness is upheld.
+        // While this method can terminate in two ways (by returning normally or
+        // by unwinding due to a panic in `f`), in both cases, `write_back` is
+        // dropped - and its `drop` called - before any other safe code can
+        // execute.
+        let copy = unsafe { ptr::read(self) }.into_inner();
+        let mut write_back = WriteBackOnDrop { copy: ManuallyDrop::new(copy), slf: self };
+
+        let ret = f(&mut write_back.copy);
+
+        drop(write_back);
+        ret
+    }
+}
+
+impl<T: Copy> Unalign<T> {
+    /// Gets a copy of the inner `T`.
+    // TODO(https://github.com/rust-lang/rust/issues/57349): Make this `const`.
+    #[inline(always)]
+    pub fn get(&self) -> T {
+        let Unalign(val) = *self;
+        val
+    }
+}
+
+impl<T: Unaligned> Deref for Unalign<T> {
+    type Target = T;
+
+    #[inline(always)]
+    fn deref(&self) -> &T {
+        // SAFETY: `deref_unchecked`'s safety requirement is that `self` is
+        // aligned to `align_of::<T>()`. `T: Unaligned` guarantees that
+        // `align_of::<T>() == 1`, and all pointers are one-aligned because all
+        // addresses are divisible by 1.
+        unsafe { self.deref_unchecked() }
+    }
+}
+
+impl<T: Unaligned> DerefMut for Unalign<T> {
+    #[inline(always)]
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: `deref_mut_unchecked`'s safety requirement is that `self` is
+        // aligned to `align_of::<T>()`. `T: Unaligned` guarantees that
+        // `align_of::<T>() == 1`, and all pointers are one-aligned because all
+        // addresses are divisible by 1.
+        unsafe { self.deref_mut_unchecked() }
+    }
+}
+
+impl<T: Unaligned + PartialOrd> PartialOrd<Unalign<T>> for Unalign<T> {
+    #[inline(always)]
+    fn partial_cmp(&self, other: &Unalign<T>) -> Option<Ordering> {
+        PartialOrd::partial_cmp(self.deref(), other.deref())
+    }
+}
+
+impl<T: Unaligned + Ord> Ord for Unalign<T> {
+    #[inline(always)]
+    fn cmp(&self, other: &Unalign<T>) -> Ordering {
+        Ord::cmp(self.deref(), other.deref())
+    }
+}
+
+impl<T: Unaligned + PartialEq> PartialEq<Unalign<T>> for Unalign<T> {
+    #[inline(always)]
+    fn eq(&self, other: &Unalign<T>) -> bool {
+        PartialEq::eq(self.deref(), other.deref())
+    }
+}
+
+impl<T: Unaligned + Eq> Eq for Unalign<T> {}
+
+impl<T: Unaligned + Hash> Hash for Unalign<T> {
+    #[inline(always)]
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: Hasher,
+    {
+        self.deref().hash(state);
+    }
+}
+
+impl<T: Unaligned + Debug> Debug for Unalign<T> {
+    #[inline(always)]
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        Debug::fmt(self.deref(), f)
+    }
+}
+
+impl<T: Unaligned + Display> Display for Unalign<T> {
+    #[inline(always)]
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        Display::fmt(self.deref(), f)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use core::panic::AssertUnwindSafe;
+
+    use super::*;
+    use crate::util::testutil::*;
+
+    /// A `T` which is guaranteed not to satisfy `align_of::<A>()`.
+    ///
+    /// It must be the case that `align_of::<T>() < align_of::<A>()` in order
+    /// fot this type to work properly.
+    #[repr(C)]
+    struct ForceUnalign<T, A> {
+        // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is
+        // placed at the minimum offset that guarantees its alignment. If
+        // `align_of::<T>() < align_of::<A>()`, then that offset will be
+        // guaranteed *not* to satisfy `align_of::<A>()`.
+        _u: u8,
+        t: T,
+        _a: [A; 0],
+    }
+
+    impl<T, A> ForceUnalign<T, A> {
+        const fn new(t: T) -> ForceUnalign<T, A> {
+            ForceUnalign { _u: 0, t, _a: [] }
+        }
+    }
+
+    #[test]
+    fn test_unalign() {
+        // Test methods that don't depend on alignment.
+        let mut u = Unalign::new(AU64(123));
+        assert_eq!(u.get(), AU64(123));
+        assert_eq!(u.into_inner(), AU64(123));
+        assert_eq!(u.get_ptr(), <*const _>::cast::<AU64>(&u));
+        assert_eq!(u.get_mut_ptr(), <*mut _>::cast::<AU64>(&mut u));
+        u.set(AU64(321));
+        assert_eq!(u.get(), AU64(321));
+
+        // Test methods that depend on alignment (when alignment is satisfied).
+        let mut u: Align<_, AU64> = Align::new(Unalign::new(AU64(123)));
+        assert_eq!(u.t.try_deref(), Some(&AU64(123)));
+        assert_eq!(u.t.try_deref_mut(), Some(&mut AU64(123)));
+        // SAFETY: The `Align<_, AU64>` guarantees proper alignment.
+        assert_eq!(unsafe { u.t.deref_unchecked() }, &AU64(123));
+        // SAFETY: The `Align<_, AU64>` guarantees proper alignment.
+        assert_eq!(unsafe { u.t.deref_mut_unchecked() }, &mut AU64(123));
+        *u.t.try_deref_mut().unwrap() = AU64(321);
+        assert_eq!(u.t.get(), AU64(321));
+
+        // Test methods that depend on alignment (when alignment is not
+        // satisfied).
+        let mut u: ForceUnalign<_, AU64> = ForceUnalign::new(Unalign::new(AU64(123)));
+        assert_eq!(u.t.try_deref(), None);
+        assert_eq!(u.t.try_deref_mut(), None);
+
+        // Test methods that depend on `T: Unaligned`.
+        let mut u = Unalign::new(123u8);
+        assert_eq!(u.try_deref(), Some(&123));
+        assert_eq!(u.try_deref_mut(), Some(&mut 123));
+        assert_eq!(u.deref(), &123);
+        assert_eq!(u.deref_mut(), &mut 123);
+        *u = 21;
+        assert_eq!(u.get(), 21);
+
+        // Test that some `Unalign` functions and methods are `const`.
+        const _UNALIGN: Unalign<u64> = Unalign::new(0);
+        const _UNALIGN_PTR: *const u64 = _UNALIGN.get_ptr();
+        const _U64: u64 = _UNALIGN.into_inner();
+        // Make sure all code is considered "used".
+        //
+        // TODO(https://github.com/rust-lang/rust/issues/104084): Remove this
+        // attribute.
+        #[allow(dead_code)]
+        const _: () = {
+            let x: Align<_, AU64> = Align::new(Unalign::new(AU64(123)));
+            // Make sure that `deref_unchecked` is `const`.
+            //
+            // SAFETY: The `Align<_, AU64>` guarantees proper alignment.
+            let au64 = unsafe { x.t.deref_unchecked() };
+            match au64 {
+                AU64(123) => {}
+                _ => unreachable!(),
+            }
+        };
+    }
+
+    #[test]
+    fn test_unalign_update() {
+        let mut u = Unalign::new(AU64(123));
+        u.update(|a| a.0 += 1);
+        assert_eq!(u.get(), AU64(124));
+
+        // Test that, even if the callback panics, the original is still
+        // correctly overwritten. Use a `Box` so that Miri is more likely to
+        // catch any unsoundness (which would likely result in two `Box`es for
+        // the same heap object, which is the sort of thing that Miri would
+        // probably catch).
+        let mut u = Unalign::new(Box::new(AU64(123)));
+        let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
+            u.update(|a| {
+                a.0 += 1;
+                panic!();
+            })
+        }));
+        assert!(res.is_err());
+        assert_eq!(u.into_inner(), Box::new(AU64(124)));
+    }
+}
diff --git a/extra_versions/crates/zerocopy/testdata/include_value/data b/extra_versions/crates/zerocopy/testdata/include_value/data
new file mode 100644
index 0000000..85df507
--- /dev/null
+++ b/extra_versions/crates/zerocopy/testdata/include_value/data
@@ -0,0 +1 @@
+abcd
\ No newline at end of file
diff --git a/extra_versions/crates/zerocopy/tests/trybuild.rs b/extra_versions/crates/zerocopy/tests/trybuild.rs
new file mode 100644
index 0000000..24abc28
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/trybuild.rs
@@ -0,0 +1,41 @@
+// Copyright 2019 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+use testutil::ToolchainVersion;
+
+#[test]
+#[cfg_attr(miri, ignore)]
+fn ui() {
+    let version = ToolchainVersion::extract_from_pwd().unwrap();
+    // See the doc comment on this method for an explanation of what this does
+    // and why we store source files in different directories.
+    let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning();
+
+    let t = trybuild::TestCases::new();
+    t.compile_fail(format!("tests/{source_files_dirname}/*.rs"));
+}
+
+// The file `invalid-impls.rs` directly includes `src/macros.rs` in order to
+// test the `impl_or_verify!` macro which is defined in that file. Specifically,
+// it tests the verification portion of that macro, which is enabled when
+// `cfg(any(feature = "derive", test))`. While `--cfg test` is of course passed
+// to the code in the file you're reading right now, `trybuild` does not pass
+// `--cfg test` when it invokes Cargo. As a result, this `trybuild` test only
+// tests the correct behavior when the "derive" feature is enabled.
+#[cfg(feature = "derive")]
+#[test]
+#[cfg_attr(miri, ignore)]
+fn ui_invalid_impls() {
+    let version = ToolchainVersion::extract_from_pwd().unwrap();
+    // See the doc comment on this method for an explanation of what this does
+    // and why we store source files in different directories.
+    let source_files_dirname = version.get_ui_source_files_dirname_and_maybe_print_warning();
+
+    let t = trybuild::TestCases::new();
+    t.compile_fail(format!("tests/{source_files_dirname}/invalid-impls/*.rs"));
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs
new file mode 100644
index 0000000..45b6138
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.rs
@@ -0,0 +1,12 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because `UnsafeCell<u32>: !FromBytes`.
+const NOT_FROM_BYTES: core::cell::UnsafeCell<u32> =
+    include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr
new file mode 100644
index 0000000..21f6443
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_not_from_bytes.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `UnsafeCell<u32>: FromBytes` is not satisfied
+  --> tests/ui-msrv/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `UnsafeCell<u32>`
+   |
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-msrv/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.rs
new file mode 100644
index 0000000..d87b306
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.rs
@@ -0,0 +1,11 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because the file is 4 bytes long, not 8.
+const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr
new file mode 100644
index 0000000..3004584
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/include_value_wrong_size.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/include_value_wrong_size.rs:11:25
+   |
+11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 4]` (32 bits)
+   = note: target type: `u64` (64 bits)
+   = note: this error originates in the macro `$crate::transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs
new file mode 100644
index 0000000..ea96390
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.rs
@@ -0,0 +1,29 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// Since some macros from `macros.rs` are unused.
+#![allow(unused)]
+
+extern crate zerocopy;
+extern crate zerocopy_derive;
+
+include!("../../../src/macros.rs");
+
+use zerocopy::*;
+use zerocopy_derive::*;
+
+fn main() {}
+
+#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+#[repr(transparent)]
+struct Foo<T>(T);
+
+impl_or_verify!(T => FromZeroes for Foo<T>);
+impl_or_verify!(T => FromBytes for Foo<T>);
+impl_or_verify!(T => AsBytes for Foo<T>);
+impl_or_verify!(T => Unaligned for Foo<T>);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr
new file mode 100644
index 0000000..c1de466
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/invalid-impls/invalid-impls.stderr
@@ -0,0 +1,127 @@
+error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+   |                                                                    ^^^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   | ------------------------------------------- in this macro invocation
+   |
+note: required because of the requirements on the impl of `zerocopy::FromZeroes` for `Foo<T>`
+  --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:10
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |          ^^^^^^^^^^
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `_::Subtrait`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:26:1
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   | ------------------------------------------- in this macro invocation
+   = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo<T>);
+   |                  ++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+   |                                                                    ^^^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   |
+note: required because of the requirements on the impl of `zerocopy::FromBytes` for `Foo<T>`
+  --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:22
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                      ^^^^^^^^^
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `_::Subtrait`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:27:1
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo<T>);
+   |                  +++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+   |                                                                    ^^^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   | ---------------------------------------- in this macro invocation
+   |
+note: required because of the requirements on the impl of `zerocopy::AsBytes` for `Foo<T>`
+  --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:33
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                 ^^^^^^^
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `_::Subtrait`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:28:1
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   | ---------------------------------------- in this macro invocation
+   = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo<T>);
+   |                  +++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+   |                                                                    ^^^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   |
+note: required because of the requirements on the impl of `zerocopy::Unaligned` for `Foo<T>`
+  --> tests/ui-msrv/invalid-impls/invalid-impls.rs:22:42
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                          ^^^^^^^^^
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-msrv/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `_::Subtrait`
+   |
+  ::: tests/ui-msrv/invalid-impls/invalid-impls.rs:29:1
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo<T>);
+   |                  +++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.rs
new file mode 100644
index 0000000..53e3eb9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.rs
@@ -0,0 +1,99 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[repr(C, align(1))]
+struct Align1;
+
+#[repr(C, align(2))]
+struct Align2;
+
+#[repr(C, align(4))]
+struct Align4;
+
+#[repr(C, align(8))]
+struct Align8;
+
+#[repr(C, align(16))]
+struct Align16;
+
+#[repr(C, align(32))]
+struct Align32;
+
+#[repr(C, align(64))]
+struct Align64;
+
+#[repr(C, align(128))]
+struct Align128;
+
+#[repr(C, align(256))]
+struct Align256;
+
+#[repr(C, align(512))]
+struct Align512;
+
+#[repr(C, align(1024))]
+struct Align1024;
+
+#[repr(C, align(2048))]
+struct Align2048;
+
+#[repr(C, align(4096))]
+struct Align4096;
+
+#[repr(C, align(8192))]
+struct Align8192;
+
+#[repr(C, align(16384))]
+struct Align16384;
+
+#[repr(C, align(32768))]
+struct Align32768;
+
+#[repr(C, align(65536))]
+struct Align65536;
+
+#[repr(C, align(131072))]
+struct Align131072;
+
+#[repr(C, align(262144))]
+struct Align262144;
+
+#[repr(C, align(524288))]
+struct Align524288;
+
+#[repr(C, align(1048576))]
+struct Align1048576;
+
+#[repr(C, align(2097152))]
+struct Align2097152;
+
+#[repr(C, align(4194304))]
+struct Align4194304;
+
+#[repr(C, align(8388608))]
+struct Align8388608;
+
+#[repr(C, align(16777216))]
+struct Align16777216;
+
+#[repr(C, align(33554432))]
+struct Align33554432;
+
+#[repr(C, align(67108864))]
+struct Align67108864;
+
+#[repr(C, align(134217728))]
+struct Align13421772;
+
+#[repr(C, align(268435456))]
+struct Align26843545;
+
+#[repr(C, align(1073741824))]
+struct Align1073741824;
+
+fn main() {}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.stderr
new file mode 100644
index 0000000..6ab6e47
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/max-align.stderr
@@ -0,0 +1,5 @@
+error[E0589]: invalid `repr(align)` attribute: larger than 2^29
+  --> tests/ui-msrv/max-align.rs:96:11
+   |
+96 | #[repr(C, align(1073741824))]
+   |           ^^^^^^^^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs
new file mode 100644
index 0000000..c4caaff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr
new file mode 100644
index 0000000..b4afbbd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-dst-not-frombytes.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-msrv/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-msrv/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs
new file mode 100644
index 0000000..0928564
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr
new file mode 100644
index 0000000..033031c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-alignment-increase.stderr
@@ -0,0 +1,36 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:39
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:54
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                                      ^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+
+error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], AU16>` in constants
+  --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:39
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> tests/ui-msrv/transmute-mut-alignment-increase.rs:19:59
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                       --------------------^^^^^^^^-
+   |                                       |                   |
+   |                                       |                   creates a temporary which is freed while still in use
+   |                                       temporary value is freed at the end of this statement
+   |                                       using this value as a constant requires that borrow lasts for `'static`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.rs
new file mode 100644
index 0000000..021b562
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.rs
@@ -0,0 +1,20 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+
+// `transmute_mut!` cannot, generally speaking, be used in const contexts.
+const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.stderr
new file mode 100644
index 0000000..30bfe45
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-const.stderr
@@ -0,0 +1,41 @@
+warning: taking a mutable reference to a `const` item
+  --> tests/ui-msrv/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(const_item_mutation)]` on by default
+   = note: each usage of a `const` item creates a new temporary
+   = note: the mutable reference will refer to this temporary, not the original `const` item
+note: `const` item defined here
+  --> tests/ui-msrv/transmute-mut-const.rs:17:1
+   |
+17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-msrv/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+
+error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], [u8; 2]>` in constants
+  --> tests/ui-msrv/transmute-mut-const.rs:20:37
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> tests/ui-msrv/transmute-mut-const.rs:20:57
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                     --------------------^^^^^^^^^^^^-
+   |                                     |                   |
+   |                                     |                   creates a temporary which is freed while still in use
+   |                                     temporary value is freed at the end of this statement
+   |                                     using this value as a constant requires that borrow lasts for `'static`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs
new file mode 100644
index 0000000..7068f10
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(u: &mut u8) -> &mut T {
+    // `transmute_mut!` requires the destination type to be concrete.
+    transmute_mut!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr
new file mode 100644
index 0000000..f6b54ce
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs
new file mode 100644
index 0000000..33a9ecd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr
new file mode 100644
index 0000000..8f0ea80
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-a-reference.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs
new file mode 100644
index 0000000..b72f129
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `AsBytes`
+const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr
new file mode 100644
index 0000000..7e2dd78
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-asbytes.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `Dst: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Dst`
+   |
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs
new file mode 100644
index 0000000..102fced
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr
new file mode 100644
index 0000000..663e085
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-not-frombytes.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
+   |
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs
new file mode 100644
index 0000000..693ccda
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr
new file mode 100644
index 0000000..cb60a82
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-dst-unsized.stderr
@@ -0,0 +1,108 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                         ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |         ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                          ^^^ required by this bound in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs
new file mode 100644
index 0000000..c31765e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let mut x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr
new file mode 100644
index 0000000..5ff7145
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-illegal-lifetime.stderr
@@ -0,0 +1,9 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-msrv/transmute-mut-illegal-lifetime.rs:14:56
+   |
+14 |     let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+   |            ----------------                            ^^^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs
new file mode 100644
index 0000000..c6eec3a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// We require that the size of the destination type is not smaller than the size
+// of the source type.
+const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr
new file mode 100644
index 0000000..2bfc218
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-decrease.stderr
@@ -0,0 +1,36 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:47
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                               ^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+
+error[E0015]: cannot call non-const fn `transmute_mut::<[u8; 2], u8>` in constants
+  --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:32
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> tests/ui-msrv/transmute-mut-size-decrease.rs:17:52
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                --------------------^^^^^^^^-
+   |                                |                   |
+   |                                |                   creates a temporary which is freed while still in use
+   |                                temporary value is freed at the end of this statement
+   |                                using this value as a constant requires that borrow lasts for `'static`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs
new file mode 100644
index 0000000..a4657c2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr
new file mode 100644
index 0000000..6e866a0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-size-increase.stderr
@@ -0,0 +1,36 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-msrv/transmute-mut-size-increase.rs:17:52
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                                    ^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+
+error[E0015]: cannot call non-const fn `transmute_mut::<u8, [u8; 2]>` in constants
+  --> tests/ui-msrv/transmute-mut-size-increase.rs:17:37
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> tests/ui-msrv/transmute-mut-size-increase.rs:17:57
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                     --------------------^^^-
+   |                                     |                   |
+   |                                     |                   creates a temporary which is freed while still in use
+   |                                     temporary value is freed at the end of this statement
+   |                                     using this value as a constant requires that borrow lasts for `'static`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs
new file mode 100644
index 0000000..aed7ded
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes, U: AsBytes + FromBytes>(t: &mut T) -> &mut U {
+    // `transmute_mut!` requires the source and destination types to be
+    // concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr
new file mode 100644
index 0000000..1162f21
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs
new file mode 100644
index 0000000..98cc520
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr
new file mode 100644
index 0000000..c500a93
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-not-references.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-src-dst-not-references.rs:17:59
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   |                                            ---------------^^^^^^-
+   |                                            |              |
+   |                                            |              expected `&mut _`, found `usize`
+   |                                            |              help: consider mutably borrowing here: `&mut 0usize`
+   |                                            expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs
new file mode 100644
index 0000000..1bebcf2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr
new file mode 100644
index 0000000..00201a6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-dst-unsized.stderr
@@ -0,0 +1,237 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                      ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |      ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by this bound in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs
new file mode 100644
index 0000000..a3ef397
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+    // `transmute_mut!` requires the source type to be concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr
new file mode 100644
index 0000000..8a9296c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-generic.stderr
@@ -0,0 +1,10 @@
+error[E0405]: cannot find trait `FromBytes` in this scope
+  --> tests/ui-msrv/transmute-mut-src-generic.rs:15:31
+   |
+15 | fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+   |                               ^^^^^^^^^ not found in this scope
+   |
+help: consider importing this trait
+   |
+11 | use zerocopy::FromBytes;
+   |
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs
new file mode 100644
index 0000000..08088d0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+fn ref_src_immutable() {
+    // `transmute_mut!` requires that its source type be a mutable reference.
+    let _: &mut u8 = transmute_mut!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr
new file mode 100644
index 0000000..8262f16
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-immutable.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-src-immutable.rs:17:37
+   |
+17 |     let _: &mut u8 = transmute_mut!(&0u8);
+   |                      ---------------^^^^-
+   |                      |              |
+   |                      |              types differ in mutability
+   |                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                      found reference `&u8`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs
new file mode 100644
index 0000000..bf8bc32
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr
new file mode 100644
index 0000000..3a6bdf7
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-a-reference.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-mut-src-not-a-reference.rs:17:53
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   |                                      ---------------^^^^^^-
+   |                                      |              |
+   |                                      |              expected `&mut _`, found `usize`
+   |                                      |              help: consider mutably borrowing here: `&mut 0usize`
+   |                                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs
new file mode 100644
index 0000000..6a14f12
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr
new file mode 100644
index 0000000..4056975
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-asbytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src`
+   |
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src`
+   |
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs
new file mode 100644
index 0000000..2ebe036
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `FromBytes`
+const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr
new file mode 100644
index 0000000..b859c41
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
+   |
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
+   |
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs
new file mode 100644
index 0000000..413dd68
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr
new file mode 100644
index 0000000..6b18695
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-mut-src-unsized.stderr
@@ -0,0 +1,198 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                      ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |      ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by this bound in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs
new file mode 100644
index 0000000..5af8859
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.rs
@@ -0,0 +1,20 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// It is unclear whether we can or should support this transmutation, especially
+// in a const context. This test ensures that even if such a transmutation
+// becomes valid due to the requisite implementations of `FromBytes` being
+// added, that we re-examine whether it should specifically be valid in a const
+// context.
+const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr
new file mode 100644
index 0000000..06b1bba
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ptr-to-usize.stderr
@@ -0,0 +1,37 @@
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize`
+   |
+   = help: the following implementations were found:
+             <usize as AsBytes>
+             <f32 as AsBytes>
+             <f64 as AsBytes>
+             <i128 as AsBytes>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize`
+   |
+   = help: the following implementations were found:
+             <usize as AsBytes>
+             <f32 as AsBytes>
+             <f64 as AsBytes>
+             <i128 as AsBytes>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs
new file mode 100644
index 0000000..bf1988c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr
new file mode 100644
index 0000000..72864e1
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-alignment-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-alignment-increase.rs:19:35
+   |
+19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs
new file mode 100644
index 0000000..bf4a0f9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: FromBytes>(u: &u8) -> &T {
+    // `transmute_ref!` requires the destination type to be concrete.
+    transmute_ref!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr
new file mode 100644
index 0000000..ec7ec74
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs
new file mode 100644
index 0000000..fa0e6e4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+fn ref_dst_mutable() {
+    // `transmute_ref!` requires that its destination type be an immutable
+    // reference.
+    let _: &mut u8 = transmute_ref!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr
new file mode 100644
index 0000000..5ccf2cd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-mutable.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs
new file mode 100644
index 0000000..de55f9a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr
new file mode 100644
index 0000000..9a61c4c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-a-reference.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs
new file mode 100644
index 0000000..d81f64d
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr
new file mode 100644
index 0000000..d317675
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-not-frombytes.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
+   |
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-msrv/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs
new file mode 100644
index 0000000..625f1fa
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr
new file mode 100644
index 0000000..78135de
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-dst-unsized.stderr
@@ -0,0 +1,94 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                         ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |         ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                                ^^^ required by this bound in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs
new file mode 100644
index 0000000..8dd191e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static u64 = zerocopy::transmute_ref!(&x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr
new file mode 100644
index 0000000..866ea56
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-illegal-lifetime.stderr
@@ -0,0 +1,9 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-msrv/transmute-ref-illegal-lifetime.rs:14:52
+   |
+14 |     let _: &'static u64 = zerocopy::transmute_ref!(&x);
+   |            ------------                            ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs
new file mode 100644
index 0000000..1d66a54
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr
new file mode 100644
index 0000000..95669f9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-size-decrease.rs:17:28
+   |
+17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs
new file mode 100644
index 0000000..cdca560
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr
new file mode 100644
index 0000000..10f0e10
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-size-increase.rs:17:33
+   |
+17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs
new file mode 100644
index 0000000..409d785
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes, U: FromBytes>(t: &T) -> &U {
+    // `transmute_ref!` requires the source and destination types to be
+    // concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr
new file mode 100644
index 0000000..eb3268f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs
new file mode 100644
index 0000000..114e917
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr
new file mode 100644
index 0000000..2c5e23b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-not-references.stderr
@@ -0,0 +1,42 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:54
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ---------------^^^^^^-
+   |                                       |              |
+   |                                       |              expected reference, found `usize`
+   |                                       |              help: consider borrowing here: `&0usize`
+   |                                       expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs
new file mode 100644
index 0000000..6bfe7ff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr
new file mode 100644
index 0000000..adfd597
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-dst-unsized.stderr
@@ -0,0 +1,195 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                      ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |      ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by this bound in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs
new file mode 100644
index 0000000..010281c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes>(t: &T) -> &u8 {
+    // `transmute_ref!` requires the source type to be concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr
new file mode 100644
index 0000000..4cb3e51
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, u8>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs
new file mode 100644
index 0000000..90661b3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr
new file mode 100644
index 0000000..0f4aeec
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-a-reference.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> tests/ui-msrv/transmute-ref-src-not-a-reference.rs:17:49
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ---------------^^^^^^-
+   |                                  |              |
+   |                                  |              expected reference, found `usize`
+   |                                  |              help: consider borrowing here: `&0usize`
+   |                                  expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs
new file mode 100644
index 0000000..6ab19f3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr
new file mode 100644
index 0000000..6b80d4f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-not-asbytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs
new file mode 100644
index 0000000..14e72b4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr
new file mode 100644
index 0000000..43bac53
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-ref-src-unsized.stderr
@@ -0,0 +1,170 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<T, U>(e: T) -> U;
+   |                      ^ required by this bound in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf::<T, U>::new`
+  --> src/macro_util.rs
+   |
+   | impl<T, U> MaxAlignsOf<T, U> {
+   |      ^ required by this bound in `MaxAlignsOf::<T, U>::new`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by this bound in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by this bound in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by this bound in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-msrv/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all function arguments must have a statically known size
+   = note: this error originates in the macro `$crate::assert_size_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.rs
new file mode 100644
index 0000000..1d56831
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: u8 = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr
new file mode 100644
index 0000000..ffa5688
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-size-decrease.rs:19:27
+   |
+19 | const DECREASE_SIZE: u8 = transmute!(AU16(0));
+   |                           ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AU16` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.rs
new file mode 100644
index 0000000..32f9363
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: AU16 = transmute!(0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.stderr
new file mode 100644
index 0000000..865d0ca
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-msrv/transmute-size-increase.rs:19:29
+   |
+19 | const INCREASE_SIZE: AU16 = transmute!(0u8);
+   |                             ^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `AU16` (16 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs
new file mode 100644
index 0000000..dd73021
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr
new file mode 100644
index 0000000..93eeda0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-msrv/transmute-src-not-asbytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-msrv/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs
new file mode 100644
index 0000000..45b6138
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.rs
@@ -0,0 +1,12 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because `UnsafeCell<u32>: !FromBytes`.
+const NOT_FROM_BYTES: core::cell::UnsafeCell<u32> =
+    include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr
new file mode 100644
index 0000000..f7c7fdd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_not_from_bytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `UnsafeCell<u32>: FromBytes` is not satisfied
+  --> tests/ui-nightly/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the trait `FromBytes` is not implemented for `UnsafeCell<u32>`
+   |     required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-nightly/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.rs
new file mode 100644
index 0000000..d87b306
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.rs
@@ -0,0 +1,11 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because the file is 4 bytes long, not 8.
+const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr
new file mode 100644
index 0000000..f592ece
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/include_value_wrong_size.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/include_value_wrong_size.rs:11:25
+   |
+11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 4]` (32 bits)
+   = note: target type: `u64` (64 bits)
+   = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs
new file mode 100644
index 0000000..ea96390
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.rs
@@ -0,0 +1,29 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// Since some macros from `macros.rs` are unused.
+#![allow(unused)]
+
+extern crate zerocopy;
+extern crate zerocopy_derive;
+
+include!("../../../src/macros.rs");
+
+use zerocopy::*;
+use zerocopy_derive::*;
+
+fn main() {}
+
+#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+#[repr(transparent)]
+struct Foo<T>(T);
+
+impl_or_verify!(T => FromZeroes for Foo<T>);
+impl_or_verify!(T => FromBytes for Foo<T>);
+impl_or_verify!(T => AsBytes for Foo<T>);
+impl_or_verify!(T => Unaligned for Foo<T>);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr
new file mode 100644
index 0000000..1c91309
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/invalid-impls/invalid-impls.stderr
@@ -0,0 +1,107 @@
+error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:26:37
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   |                                     ^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::FromZeroes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::FromZeroes`
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:10
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-nightly/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:26:1
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   | ------------------------------------------- in this macro invocation
+   = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo<T>);
+   |                  ++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:27:36
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   |                                    ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::FromBytes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::FromBytes`
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:22
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                      ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-nightly/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:27:1
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo<T>);
+   |                  +++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:28:34
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   |                                  ^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::AsBytes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::AsBytes`
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:33
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                 ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-nightly/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:28:1
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   | ---------------------------------------- in this macro invocation
+   = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo<T>);
+   |                  +++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:29:36
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   |                                    ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo<T>: zerocopy::Unaligned`
+   |
+note: required for `Foo<T>` to implement `zerocopy::Unaligned`
+  --> tests/ui-nightly/invalid-impls/invalid-impls.rs:22:42
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                          ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-nightly/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-nightly/invalid-impls/invalid-impls.rs:29:1
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo<T>);
+   |                  +++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.rs
new file mode 100644
index 0000000..53e3eb9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.rs
@@ -0,0 +1,99 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[repr(C, align(1))]
+struct Align1;
+
+#[repr(C, align(2))]
+struct Align2;
+
+#[repr(C, align(4))]
+struct Align4;
+
+#[repr(C, align(8))]
+struct Align8;
+
+#[repr(C, align(16))]
+struct Align16;
+
+#[repr(C, align(32))]
+struct Align32;
+
+#[repr(C, align(64))]
+struct Align64;
+
+#[repr(C, align(128))]
+struct Align128;
+
+#[repr(C, align(256))]
+struct Align256;
+
+#[repr(C, align(512))]
+struct Align512;
+
+#[repr(C, align(1024))]
+struct Align1024;
+
+#[repr(C, align(2048))]
+struct Align2048;
+
+#[repr(C, align(4096))]
+struct Align4096;
+
+#[repr(C, align(8192))]
+struct Align8192;
+
+#[repr(C, align(16384))]
+struct Align16384;
+
+#[repr(C, align(32768))]
+struct Align32768;
+
+#[repr(C, align(65536))]
+struct Align65536;
+
+#[repr(C, align(131072))]
+struct Align131072;
+
+#[repr(C, align(262144))]
+struct Align262144;
+
+#[repr(C, align(524288))]
+struct Align524288;
+
+#[repr(C, align(1048576))]
+struct Align1048576;
+
+#[repr(C, align(2097152))]
+struct Align2097152;
+
+#[repr(C, align(4194304))]
+struct Align4194304;
+
+#[repr(C, align(8388608))]
+struct Align8388608;
+
+#[repr(C, align(16777216))]
+struct Align16777216;
+
+#[repr(C, align(33554432))]
+struct Align33554432;
+
+#[repr(C, align(67108864))]
+struct Align67108864;
+
+#[repr(C, align(134217728))]
+struct Align13421772;
+
+#[repr(C, align(268435456))]
+struct Align26843545;
+
+#[repr(C, align(1073741824))]
+struct Align1073741824;
+
+fn main() {}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.stderr
new file mode 100644
index 0000000..c11eed5
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/max-align.stderr
@@ -0,0 +1,5 @@
+error[E0589]: invalid `repr(align)` attribute: larger than 2^29
+  --> tests/ui-nightly/max-align.rs:96:17
+   |
+96 | #[repr(C, align(1073741824))]
+   |                 ^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs
new file mode 100644
index 0000000..c4caaff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr
new file mode 100644
index 0000000..70bec21
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-nightly/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^
+   |                                         |
+   |                                         the trait `FromBytes` is not implemented for `NotZerocopy`
+   |                                         required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-nightly/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs
new file mode 100644
index 0000000..0928564
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr
new file mode 100644
index 0000000..0666f8b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-alignment-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-alignment-increase.rs:19:39
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.rs
new file mode 100644
index 0000000..021b562
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.rs
@@ -0,0 +1,20 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+
+// `transmute_mut!` cannot, generally speaking, be used in const contexts.
+const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.stderr
new file mode 100644
index 0000000..61a34b9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-const.stderr
@@ -0,0 +1,33 @@
+warning: taking a mutable reference to a `const` item
+  --> tests/ui-nightly/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary
+   = note: the mutable reference will refer to this temporary, not the original `const` item
+note: `const` item defined here
+  --> tests/ui-nightly/transmute-mut-const.rs:17:1
+   |
+17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(const_item_mutation)]` on by default
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-nightly/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+   = note: this compiler was built on 2024-06-18; consider upgrading it if it is out of date
+
+error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants
+  --> tests/ui-nightly/transmute-mut-const.rs:20:37
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs
new file mode 100644
index 0000000..7068f10
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(u: &mut u8) -> &mut T {
+    // `transmute_mut!` requires the destination type to be concrete.
+    transmute_mut!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr
new file mode 100644
index 0000000..f278558
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs
new file mode 100644
index 0000000..33a9ecd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr
new file mode 100644
index 0000000..a84547b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-a-reference.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs
new file mode 100644
index 0000000..b72f129
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `AsBytes`
+const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr
new file mode 100644
index 0000000..7de5da6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-asbytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Dst: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    the trait `AsBytes` is not implemented for `Dst`
+   |                                    required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs
new file mode 100644
index 0000000..102fced
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr
new file mode 100644
index 0000000..9df4ebc
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      the trait `FromBytes` is not implemented for `Dst`
+   |                                      required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs
new file mode 100644
index 0000000..693ccda
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr
new file mode 100644
index 0000000..5e3fbb4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-dst-unsized.stderr
@@ -0,0 +1,86 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                          ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs
new file mode 100644
index 0000000..c31765e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let mut x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr
new file mode 100644
index 0000000..b826fcc
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-illegal-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-nightly/transmute-mut-illegal-lifetime.rs:14:56
+   |
+12 |     let mut x = 0u64;
+   |         ----- binding `x` declared here
+13 |     // It is illegal to increase the lifetime scope.
+14 |     let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+   |            ----------------                            ^^^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs
new file mode 100644
index 0000000..c6eec3a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// We require that the size of the destination type is not smaller than the size
+// of the source type.
+const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr
new file mode 100644
index 0000000..ac1e35c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-size-decrease.rs:17:32
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs
new file mode 100644
index 0000000..a4657c2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr
new file mode 100644
index 0000000..d343bd6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-size-increase.rs:17:37
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs
new file mode 100644
index 0000000..aed7ded
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes, U: AsBytes + FromBytes>(t: &mut T) -> &mut U {
+    // `transmute_mut!` requires the source and destination types to be
+    // concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr
new file mode 100644
index 0000000..e3f3a3f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs
new file mode 100644
index 0000000..98cc520
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr
new file mode 100644
index 0000000..bdd3f42
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-not-references.stderr
@@ -0,0 +1,44 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:59
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   |                                            ---------------^^^^^^-
+   |                                            |              |
+   |                                            |              expected `&mut _`, found `usize`
+   |                                            expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
+help: consider mutably borrowing here
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize);
+   |                                                           ++++
+
+warning: this function depends on never type fallback being `()`
+  --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:1
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: FromBytes` will fail
+  --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:44
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-mut-src-dst-not-references.rs:17:44
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   |                                            ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs
new file mode 100644
index 0000000..1bebcf2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr
new file mode 100644
index 0000000..2fe6658
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-dst-unsized.stderr
@@ -0,0 +1,231 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                          ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs
new file mode 100644
index 0000000..a3ef397
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+    // `transmute_mut!` requires the source type to be concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr
new file mode 100644
index 0000000..c06d775
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-generic.stderr
@@ -0,0 +1,10 @@
+error[E0405]: cannot find trait `FromBytes` in this scope
+  --> tests/ui-nightly/transmute-mut-src-generic.rs:15:31
+   |
+15 | fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+   |                               ^^^^^^^^^ not found in this scope
+   |
+help: consider importing this trait
+   |
+11 + use zerocopy::FromBytes;
+   |
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs
new file mode 100644
index 0000000..08088d0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+fn ref_src_immutable() {
+    // `transmute_mut!` requires that its source type be a mutable reference.
+    let _: &mut u8 = transmute_mut!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr
new file mode 100644
index 0000000..abaac99
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-immutable.stderr
@@ -0,0 +1,40 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:37
+   |
+17 |     let _: &mut u8 = transmute_mut!(&0u8);
+   |                      ---------------^^^^-
+   |                      |              |
+   |                      |              types differ in mutability
+   |                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                      found reference `&u8`
+
+warning: this function depends on never type fallback being `()`
+  --> tests/ui-nightly/transmute-mut-src-immutable.rs:15:1
+   |
+15 | fn ref_src_immutable() {
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: FromBytes` will fail
+  --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:22
+   |
+17 |     let _: &mut u8 = transmute_mut!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-mut-src-immutable.rs:17:22
+   |
+17 |     let _: &mut u8 = transmute_mut!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs
new file mode 100644
index 0000000..bf8bc32
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr
new file mode 100644
index 0000000..8fc4476
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-a-reference.stderr
@@ -0,0 +1,44 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:53
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   |                                      ---------------^^^^^^-
+   |                                      |              |
+   |                                      |              expected `&mut _`, found `usize`
+   |                                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
+help: consider mutably borrowing here
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize);
+   |                                                     ++++
+
+warning: this function depends on never type fallback being `()`
+  --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:1
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: FromBytes` will fail
+  --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:38
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: this warning originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-mut-src-not-a-reference.rs:17:38
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs
new file mode 100644
index 0000000..6a14f12
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr
new file mode 100644
index 0000000..0b4154b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    the trait `AsBytes` is not implemented for `Src`
+   |                                    required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs
new file mode 100644
index 0000000..2ebe036
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `FromBytes`
+const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr
new file mode 100644
index 0000000..858fc50
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-not-frombytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      the trait `FromBytes` is not implemented for `Src`
+   |                                      required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs
new file mode 100644
index 0000000..413dd68
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr
new file mode 100644
index 0000000..b859994
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-mut-src-unsized.stderr
@@ -0,0 +1,158 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs
new file mode 100644
index 0000000..5af8859
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.rs
@@ -0,0 +1,20 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// It is unclear whether we can or should support this transmutation, especially
+// in a const context. This test ensures that even if such a transmutation
+// becomes valid due to the requisite implementations of `FromBytes` being
+// added, that we re-examine whether it should specifically be valid in a const
+// context.
+const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr
new file mode 100644
index 0000000..2fcba2f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ptr-to-usize.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                              |
+   |                              the trait `AsBytes` is not implemented for `*const usize`
+   |                              required by a bound introduced by this call
+   |
+   = help: the trait `AsBytes` is implemented for `usize`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize`
+   |
+   = help: the trait `AsBytes` is implemented for `usize`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs
new file mode 100644
index 0000000..bf1988c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr
new file mode 100644
index 0000000..1cef246
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-alignment-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-alignment-increase.rs:19:35
+   |
+19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs
new file mode 100644
index 0000000..bf4a0f9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: FromBytes>(u: &u8) -> &T {
+    // `transmute_ref!` requires the destination type to be concrete.
+    transmute_ref!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr
new file mode 100644
index 0000000..4c94d50
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs
new file mode 100644
index 0000000..fa0e6e4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+fn ref_dst_mutable() {
+    // `transmute_ref!` requires that its destination type be an immutable
+    // reference.
+    let _: &mut u8 = transmute_ref!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr
new file mode 100644
index 0000000..0cbdd17
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-mutable.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs
new file mode 100644
index 0000000..de55f9a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr
new file mode 100644
index 0000000..847d547
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-a-reference.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs
new file mode 100644
index 0000000..d81f64d
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr
new file mode 100644
index 0000000..a09f996
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                          |
+   |                                          the trait `FromBytes` is not implemented for `NotZerocopy`
+   |                                          required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-nightly/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs
new file mode 100644
index 0000000..625f1fa
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr
new file mode 100644
index 0000000..1e97b5b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-dst-unsized.stderr
@@ -0,0 +1,69 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            |
+   |                            doesn't have a size known at compile-time
+   |                            required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                                ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs
new file mode 100644
index 0000000..8dd191e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static u64 = zerocopy::transmute_ref!(&x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr
new file mode 100644
index 0000000..e16a557
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-illegal-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-nightly/transmute-ref-illegal-lifetime.rs:14:52
+   |
+12 |     let x = 0u64;
+   |         - binding `x` declared here
+13 |     // It is illegal to increase the lifetime scope.
+14 |     let _: &'static u64 = zerocopy::transmute_ref!(&x);
+   |            ------------                            ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs
new file mode 100644
index 0000000..1d66a54
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr
new file mode 100644
index 0000000..793ecc5
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-size-decrease.rs:17:28
+   |
+17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs
new file mode 100644
index 0000000..cdca560
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr
new file mode 100644
index 0000000..40c69f6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-size-increase.rs:17:33
+   |
+17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs
new file mode 100644
index 0000000..409d785
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes, U: FromBytes>(t: &T) -> &U {
+    // `transmute_ref!` requires the source and destination types to be
+    // concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr
new file mode 100644
index 0000000..6a3a4fd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs
new file mode 100644
index 0000000..114e917
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr
new file mode 100644
index 0000000..94a7387
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-not-references.stderr
@@ -0,0 +1,85 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:54
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ---------------^^^^^^-
+   |                                       |              |
+   |                                       |              expected `&_`, found `usize`
+   |                                       expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
+help: consider borrowing here
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize);
+   |                                                      +
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: this function depends on never type fallback being `()`
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:1
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: AsBytes` will fail
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs
new file mode 100644
index 0000000..6bfe7ff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr
new file mode 100644
index 0000000..cb1e443
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-dst-unsized.stderr
@@ -0,0 +1,183 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                                ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs
new file mode 100644
index 0000000..010281c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes>(t: &T) -> &u8 {
+    // `transmute_ref!` requires the source type to be concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr
new file mode 100644
index 0000000..a168f44
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, u8>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs
new file mode 100644
index 0000000..90661b3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr
new file mode 100644
index 0000000..3418f21
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-a-reference.stderr
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:49
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ---------------^^^^^^-
+   |                                  |              |
+   |                                  |              expected `&_`, found `usize`
+   |                                  expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
+help: consider borrowing here
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize);
+   |                                                 +
+
+warning: this function depends on never type fallback being `()`
+  --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:1
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the types explicitly
+note: in edition 2024, the requirement `!: AsBytes` will fail
+  --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:34
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(dependency_on_unit_never_type_fallback)]` on by default
+   = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:34
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
+   = note: this warning originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: never type fallback affects this call to an `unsafe` function
+  --> tests/ui-nightly/transmute-ref-src-not-a-reference.rs:17:34
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
+   = help: specify the type explicitly
+   = note: this warning originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs
new file mode 100644
index 0000000..6ab19f3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr
new file mode 100644
index 0000000..5ae6b5a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                 |
+   |                                 the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |                                 required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs
new file mode 100644
index 0000000..14e72b4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr
new file mode 100644
index 0000000..3ce31ca
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-ref-src-unsized.stderr
@@ -0,0 +1,127 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               doesn't have a size known at compile-time
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-nightly/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               doesn't have a size known at compile-time
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.rs
new file mode 100644
index 0000000..1d56831
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: u8 = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr
new file mode 100644
index 0000000..83742d7
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-size-decrease.rs:19:27
+   |
+19 | const DECREASE_SIZE: u8 = transmute!(AU16(0));
+   |                           ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AU16` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.rs
new file mode 100644
index 0000000..32f9363
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: AU16 = transmute!(0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.stderr
new file mode 100644
index 0000000..230bb17
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-nightly/transmute-size-increase.rs:19:29
+   |
+19 | const INCREASE_SIZE: AU16 = transmute!(0u8);
+   |                             ^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `AU16` (16 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs
new file mode 100644
index 0000000..dd73021
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr
new file mode 100644
index 0000000..20f1b18
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-nightly/transmute-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |                                required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-nightly/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs
new file mode 100644
index 0000000..45b6138
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.rs
@@ -0,0 +1,12 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because `UnsafeCell<u32>: !FromBytes`.
+const NOT_FROM_BYTES: core::cell::UnsafeCell<u32> =
+    include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr
new file mode 100644
index 0000000..4bb4e24
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_not_from_bytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `UnsafeCell<u32>: FromBytes` is not satisfied
+  --> tests/ui-stable/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     the trait `FromBytes` is not implemented for `UnsafeCell<u32>`
+   |     required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-stable/include_value_not_from_bytes.rs:12:5
+   |
+12 |     include_value!("../../testdata/include_value/data");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.rs b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.rs
new file mode 100644
index 0000000..d87b306
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.rs
@@ -0,0 +1,11 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#[macro_use]
+extern crate zerocopy;
+
+fn main() {}
+
+// Should fail because the file is 4 bytes long, not 8.
+const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.stderr
new file mode 100644
index 0000000..956d74c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/include_value_wrong_size.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/include_value_wrong_size.rs:11:25
+   |
+11 | const WRONG_SIZE: u64 = include_value!("../../testdata/include_value/data");
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 4]` (32 bits)
+   = note: target type: `u64` (64 bits)
+   = note: this error originates in the macro `$crate::transmute` which comes from the expansion of the macro `include_value` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs b/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs
new file mode 100644
index 0000000..ea96390
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.rs
@@ -0,0 +1,29 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+// Since some macros from `macros.rs` are unused.
+#![allow(unused)]
+
+extern crate zerocopy;
+extern crate zerocopy_derive;
+
+include!("../../../src/macros.rs");
+
+use zerocopy::*;
+use zerocopy_derive::*;
+
+fn main() {}
+
+#[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+#[repr(transparent)]
+struct Foo<T>(T);
+
+impl_or_verify!(T => FromZeroes for Foo<T>);
+impl_or_verify!(T => FromBytes for Foo<T>);
+impl_or_verify!(T => AsBytes for Foo<T>);
+impl_or_verify!(T => Unaligned for Foo<T>);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr
new file mode 100644
index 0000000..c7ba84b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/invalid-impls/invalid-impls.stderr
@@ -0,0 +1,107 @@
+error[E0277]: the trait bound `T: zerocopy::FromZeroes` is not satisfied
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:26:37
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   |                                     ^^^^^^ the trait `zerocopy::FromZeroes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::FromZeroes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::FromZeroes`
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:10
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |          ^^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-stable/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-stable/invalid-impls/invalid-impls.rs:26:1
+   |
+26 | impl_or_verify!(T => FromZeroes for Foo<T>);
+   | ------------------------------------------- in this macro invocation
+   = note: this error originates in the derive macro `FromZeroes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+26 | impl_or_verify!(T: zerocopy::FromZeroes => FromZeroes for Foo<T>);
+   |                  ++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::FromBytes` is not satisfied
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:27:36
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   |                                    ^^^^^^ the trait `zerocopy::FromBytes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::FromBytes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::FromBytes`
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:22
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                      ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-stable/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-stable/invalid-impls/invalid-impls.rs:27:1
+   |
+27 | impl_or_verify!(T => FromBytes for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+27 | impl_or_verify!(T: zerocopy::FromBytes => FromBytes for Foo<T>);
+   |                  +++++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::AsBytes` is not satisfied
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:28:34
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   |                                  ^^^^^^ the trait `zerocopy::AsBytes` is not implemented for `T`, which is required by `Foo<T>: zerocopy::AsBytes`
+   |
+note: required for `Foo<T>` to implement `zerocopy::AsBytes`
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:33
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                 ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-stable/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-stable/invalid-impls/invalid-impls.rs:28:1
+   |
+28 | impl_or_verify!(T => AsBytes for Foo<T>);
+   | ---------------------------------------- in this macro invocation
+   = note: this error originates in the derive macro `AsBytes` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+28 | impl_or_verify!(T: zerocopy::AsBytes => AsBytes for Foo<T>);
+   |                  +++++++++++++++++++
+
+error[E0277]: the trait bound `T: zerocopy::Unaligned` is not satisfied
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:29:36
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   |                                    ^^^^^^ the trait `zerocopy::Unaligned` is not implemented for `T`, which is required by `Foo<T>: zerocopy::Unaligned`
+   |
+note: required for `Foo<T>` to implement `zerocopy::Unaligned`
+  --> tests/ui-stable/invalid-impls/invalid-impls.rs:22:42
+   |
+22 | #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)]
+   |                                          ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
+note: required by a bound in `_::Subtrait`
+  --> tests/ui-stable/invalid-impls/../../../src/macros.rs
+   |
+   |             trait Subtrait: $trait {}
+   |                             ^^^^^^ required by this bound in `Subtrait`
+   |
+  ::: tests/ui-stable/invalid-impls/invalid-impls.rs:29:1
+   |
+29 | impl_or_verify!(T => Unaligned for Foo<T>);
+   | ------------------------------------------ in this macro invocation
+   = note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `impl_or_verify` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider restricting type parameter `T`
+   |
+29 | impl_or_verify!(T: zerocopy::Unaligned => Unaligned for Foo<T>);
+   |                  +++++++++++++++++++++
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/max-align.rs b/extra_versions/crates/zerocopy/tests/ui-stable/max-align.rs
new file mode 100644
index 0000000..53e3eb9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/max-align.rs
@@ -0,0 +1,99 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[repr(C, align(1))]
+struct Align1;
+
+#[repr(C, align(2))]
+struct Align2;
+
+#[repr(C, align(4))]
+struct Align4;
+
+#[repr(C, align(8))]
+struct Align8;
+
+#[repr(C, align(16))]
+struct Align16;
+
+#[repr(C, align(32))]
+struct Align32;
+
+#[repr(C, align(64))]
+struct Align64;
+
+#[repr(C, align(128))]
+struct Align128;
+
+#[repr(C, align(256))]
+struct Align256;
+
+#[repr(C, align(512))]
+struct Align512;
+
+#[repr(C, align(1024))]
+struct Align1024;
+
+#[repr(C, align(2048))]
+struct Align2048;
+
+#[repr(C, align(4096))]
+struct Align4096;
+
+#[repr(C, align(8192))]
+struct Align8192;
+
+#[repr(C, align(16384))]
+struct Align16384;
+
+#[repr(C, align(32768))]
+struct Align32768;
+
+#[repr(C, align(65536))]
+struct Align65536;
+
+#[repr(C, align(131072))]
+struct Align131072;
+
+#[repr(C, align(262144))]
+struct Align262144;
+
+#[repr(C, align(524288))]
+struct Align524288;
+
+#[repr(C, align(1048576))]
+struct Align1048576;
+
+#[repr(C, align(2097152))]
+struct Align2097152;
+
+#[repr(C, align(4194304))]
+struct Align4194304;
+
+#[repr(C, align(8388608))]
+struct Align8388608;
+
+#[repr(C, align(16777216))]
+struct Align16777216;
+
+#[repr(C, align(33554432))]
+struct Align33554432;
+
+#[repr(C, align(67108864))]
+struct Align67108864;
+
+#[repr(C, align(134217728))]
+struct Align13421772;
+
+#[repr(C, align(268435456))]
+struct Align26843545;
+
+#[repr(C, align(1073741824))]
+struct Align1073741824;
+
+fn main() {}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/max-align.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/max-align.stderr
new file mode 100644
index 0000000..7e83b2f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/max-align.stderr
@@ -0,0 +1,5 @@
+error[E0589]: invalid `repr(align)` attribute: larger than 2^29
+  --> tests/ui-stable/max-align.rs:96:17
+   |
+96 | #[repr(C, align(1073741824))]
+   |                 ^^^^^^^^^^
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs
new file mode 100644
index 0000000..c4caaff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr
new file mode 100644
index 0000000..6b1e046
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-stable/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^
+   |                                         |
+   |                                         the trait `FromBytes` is not implemented for `NotZerocopy`
+   |                                         required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-stable/transmute-dst-not-frombytes.rs:18:41
+   |
+18 | const DST_NOT_FROM_BYTES: NotZerocopy = transmute!(AU16(0));
+   |                                         ^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs
new file mode 100644
index 0000000..0928564
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr
new file mode 100644
index 0000000..252fec9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-alignment-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-alignment-increase.rs:19:39
+   |
+19 | const INCREASE_ALIGNMENT: &mut AU16 = transmute_mut!(&mut [0u8; 2]);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.rs
new file mode 100644
index 0000000..021b562
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.rs
@@ -0,0 +1,20 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+
+// `transmute_mut!` cannot, generally speaking, be used in const contexts.
+const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.stderr
new file mode 100644
index 0000000..076dcf5
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-const.stderr
@@ -0,0 +1,31 @@
+warning: taking a mutable reference to a `const` item
+  --> tests/ui-stable/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary
+   = note: the mutable reference will refer to this temporary, not the original `const` item
+note: `const` item defined here
+  --> tests/ui-stable/transmute-mut-const.rs:17:1
+   |
+17 | const ARRAY_OF_U8S: [u8; 2] = [0u8; 2];
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(const_item_mutation)]` on by default
+
+error[E0658]: mutable references are not allowed in constants
+  --> tests/ui-stable/transmute-mut-const.rs:20:52
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                                    ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+
+error[E0015]: cannot call non-const fn `transmute_mut::<'_, '_, [u8; 2], [u8; 2]>` in constants
+  --> tests/ui-stable/transmute-mut-const.rs:20:37
+   |
+20 | const CONST_CONTEXT: &mut [u8; 2] = transmute_mut!(&mut ARRAY_OF_U8S);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs
new file mode 100644
index 0000000..7068f10
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(u: &mut u8) -> &mut T {
+    // `transmute_mut!` requires the destination type to be concrete.
+    transmute_mut!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr
new file mode 100644
index 0000000..0000eb0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-dst-generic.rs:17:5
+   |
+17 |     transmute_mut!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs
new file mode 100644
index 0000000..33a9ecd
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr
new file mode 100644
index 0000000..14ee444
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-a-reference.stderr
@@ -0,0 +1,39 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_mut!(&mut 0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&mut _`
+   |
+   = note:           expected type `usize`
+           found mutable reference `&mut _`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs
new file mode 100644
index 0000000..b72f129
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `AsBytes`
+const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr
new file mode 100644
index 0000000..6ea5a2f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-asbytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Dst: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    the trait `AsBytes` is not implemented for `Dst`
+   |                                    required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-stable/transmute-mut-dst-not-asbytes.rs:24:36
+   |
+24 | const DST_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs
new file mode 100644
index 0000000..102fced
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr
new file mode 100644
index 0000000..a8e39ba
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      the trait `FromBytes` is not implemented for `Dst`
+   |                                      required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+             ManuallyDrop<T>
+           and $N others
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-stable/transmute-mut-dst-not-frombytes.rs:24:38
+   |
+24 | const DST_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs
new file mode 100644
index 0000000..693ccda
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr
new file mode 100644
index 0000000..19b88e7
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-dst-unsized.stderr
@@ -0,0 +1,86 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-dst-unsized.rs:17:32
+   |
+17 | const DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8; 1]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                          ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs
new file mode 100644
index 0000000..c31765e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let mut x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr
new file mode 100644
index 0000000..7f12813
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-illegal-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-stable/transmute-mut-illegal-lifetime.rs:14:56
+   |
+12 |     let mut x = 0u64;
+   |         ----- binding `x` declared here
+13 |     // It is illegal to increase the lifetime scope.
+14 |     let _: &'static mut u64 = zerocopy::transmute_mut!(&mut x);
+   |            ----------------                            ^^^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs
new file mode 100644
index 0000000..c6eec3a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// We require that the size of the destination type is not smaller than the size
+// of the source type.
+const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr
new file mode 100644
index 0000000..2399913
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-size-decrease.rs:17:32
+   |
+17 | const DECREASE_SIZE: &mut u8 = transmute_mut!(&mut [0u8; 2]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs
new file mode 100644
index 0000000..a4657c2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr
new file mode 100644
index 0000000..1427c7b
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-size-increase.rs:17:37
+   |
+17 | const INCREASE_SIZE: &mut [u8; 2] = transmute_mut!(&mut 0u8);
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs
new file mode 100644
index 0000000..aed7ded
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes, U: AsBytes + FromBytes>(t: &mut T) -> &mut U {
+    // `transmute_mut!` requires the source and destination types to be
+    // concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr
new file mode 100644
index 0000000..ddb8bb6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-mut-src-dst-generic.rs:18:5
+   |
+18 |     transmute_mut!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs
new file mode 100644
index 0000000..98cc520
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr
new file mode 100644
index 0000000..c0d9e0f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-not-references.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-src-dst-not-references.rs:17:59
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(0usize);
+   |                                            ---------------^^^^^^-
+   |                                            |              |
+   |                                            |              expected `&mut _`, found `usize`
+   |                                            expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
+help: consider mutably borrowing here
+   |
+17 | const SRC_DST_NOT_REFERENCES: &mut usize = transmute_mut!(&mut 0usize);
+   |                                                           ++++
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs
new file mode 100644
index 0000000..1bebcf2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr
new file mode 100644
index 0000000..0cb8362
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-dst-unsized.stderr
@@ -0,0 +1,231 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertDstIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    doesn't have a size known at compile-time
+   |                                    required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-dst-unsized.rs:17:36
+   |
+17 | const SRC_DST_UNSIZED: &mut [u8] = transmute_mut!(&mut [0u8][..]);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                          ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs
new file mode 100644
index 0000000..a3ef397
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_mut, AsBytes};
+
+fn main() {}
+
+fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+    // `transmute_mut!` requires the source type to be concrete.
+    transmute_mut!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr
new file mode 100644
index 0000000..fc4809e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-generic.stderr
@@ -0,0 +1,10 @@
+error[E0405]: cannot find trait `FromBytes` in this scope
+  --> tests/ui-stable/transmute-mut-src-generic.rs:15:31
+   |
+15 | fn transmute_mut<T: AsBytes + FromBytes>(t: &mut T) -> &mut u8 {
+   |                               ^^^^^^^^^ not found in this scope
+   |
+help: consider importing this trait
+   |
+11 + use zerocopy::FromBytes;
+   |
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs
new file mode 100644
index 0000000..08088d0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+fn ref_src_immutable() {
+    // `transmute_mut!` requires that its source type be a mutable reference.
+    let _: &mut u8 = transmute_mut!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr
new file mode 100644
index 0000000..0115c79
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-immutable.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-src-immutable.rs:17:37
+   |
+17 |     let _: &mut u8 = transmute_mut!(&0u8);
+   |                      ---------------^^^^-
+   |                      |              |
+   |                      |              types differ in mutability
+   |                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                      found reference `&u8`
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs
new file mode 100644
index 0000000..bf8bc32
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr
new file mode 100644
index 0000000..8c1d9b4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-a-reference.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-mut-src-not-a-reference.rs:17:53
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(0usize);
+   |                                      ---------------^^^^^^-
+   |                                      |              |
+   |                                      |              expected `&mut _`, found `usize`
+   |                                      expected due to this
+   |
+   = note: expected mutable reference `&mut _`
+                           found type `usize`
+help: consider mutably borrowing here
+   |
+17 | const SRC_NOT_A_REFERENCE: &mut u8 = transmute_mut!(&mut 0usize);
+   |                                                     ++++
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs
new file mode 100644
index 0000000..6a14f12
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr
new file mode 100644
index 0000000..a428ae2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                    |
+   |                                    the trait `AsBytes` is not implemented for `Src`
+   |                                    required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `Src`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-not-asbytes.rs:24:36
+   |
+24 | const SRC_NOT_AS_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs
new file mode 100644
index 0000000..2ebe036
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+#[derive(zerocopy::AsBytes)]
+#[repr(C)]
+struct Src;
+
+#[derive(zerocopy::FromZeroes, zerocopy::FromBytes, zerocopy::AsBytes)]
+#[repr(C)]
+struct Dst;
+
+// `transmute_mut` requires that the source type implements `FromBytes`
+const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr
new file mode 100644
index 0000000..6a21ff1
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-not-frombytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                      |
+   |                                      the trait `FromBytes` is not implemented for `Src`
+   |                                      required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `Src: FromBytes` is not satisfied
+  --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             Dst
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-not-frombytes.rs:24:38
+   |
+24 | const SRC_NOT_FROM_BYTES: &mut Dst = transmute_mut!(&mut Src);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs
new file mode 100644
index 0000000..413dd68
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_mut;
+
+fn main() {}
+
+// `transmute_mut!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr
new file mode 100644
index 0000000..07069ec
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-mut-src-unsized.stderr
@@ -0,0 +1,158 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsFromBytes`
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertSrcIsAsBytes`
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsAsBytes`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-mut-src-unsized.rs:16:35
+   |
+16 | const SRC_UNSIZED: &mut [u8; 1] = transmute_mut!(&mut [0u8][..]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                   |
+   |                                   doesn't have a size known at compile-time
+   |                                   required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_mut`
+  --> src/macro_util.rs
+   |
+   | pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                               ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_mut`
+   = note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs
new file mode 100644
index 0000000..5af8859
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.rs
@@ -0,0 +1,20 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// It is unclear whether we can or should support this transmutation, especially
+// in a const context. This test ensures that even if such a transmutation
+// becomes valid due to the requisite implementations of `FromBytes` being
+// added, that we re-examine whether it should specifically be valid in a const
+// context.
+const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr
new file mode 100644
index 0000000..4f4d583
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ptr-to-usize.stderr
@@ -0,0 +1,30 @@
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                              |
+   |                              the trait `AsBytes` is not implemented for `*const usize`
+   |                              required by a bound introduced by this call
+   |
+   = help: the trait `AsBytes` is implemented for `usize`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize`
+   |
+   = help: the trait `AsBytes` is implemented for `usize`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ptr-to-usize.rs:20:30
+   |
+20 | const POINTER_VALUE: usize = transmute!(&0usize as *const usize);
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs
new file mode 100644
index 0000000..bf1988c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a type of smaller
+// alignment to one of larger alignment.
+const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr
new file mode 100644
index 0000000..a34c406
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-alignment-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-alignment-increase.rs:19:35
+   |
+19 | const INCREASE_ALIGNMENT: &AU16 = transmute_ref!(&[0u8; 2]);
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<[u8; 2]>` (8 bits)
+   = note: target type: `MaxAlignsOf<[u8; 2], AU16>` (16 bits)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs
new file mode 100644
index 0000000..bf4a0f9
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: FromBytes>(u: &u8) -> &T {
+    // `transmute_ref!` requires the destination type to be concrete.
+    transmute_ref!(u)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr
new file mode 100644
index 0000000..e30b9f6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `T` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-dst-generic.rs:17:5
+   |
+17 |     transmute_ref!(u)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<u8>` (8 bits)
+   = note: target type: `MaxAlignsOf<u8, T>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs
new file mode 100644
index 0000000..fa0e6e4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+fn ref_dst_mutable() {
+    // `transmute_ref!` requires that its destination type be an immutable
+    // reference.
+    let _: &mut u8 = transmute_ref!(&0u8);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr
new file mode 100644
index 0000000..c70f6ea
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-mutable.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-mutable.rs:18:22
+   |
+18 |     let _: &mut u8 = transmute_ref!(&0u8);
+   |                      ^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected mutable reference `&mut u8`
+                      found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs
new file mode 100644
index 0000000..de55f9a
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into a non-reference
+// destination type.
+const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr
new file mode 100644
index 0000000..ab3f90c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-a-reference.stderr
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-dst-not-a-reference.rs:17:36
+   |
+17 | const DST_NOT_A_REFERENCE: usize = transmute_ref!(&0u8);
+   |                                    ^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs
new file mode 100644
index 0000000..d81f64d
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the destination type implements `FromBytes`
+const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr
new file mode 100644
index 0000000..ac8ebad
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-not-frombytes.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
+  --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                          |
+   |                                          the trait `FromBytes` is not implemented for `NotZerocopy`
+   |                                          required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `FromBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-stable/transmute-ref-dst-not-frombytes.rs:18:42
+   |
+18 | const DST_NOT_FROM_BYTES: &NotZerocopy = transmute_ref!(&AU16(0));
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs
new file mode 100644
index 0000000..625f1fa
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting into an unsized destination
+// type.
+const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr
new file mode 100644
index 0000000..71cae85
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-dst-unsized.stderr
@@ -0,0 +1,69 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                            |
+   |                            doesn't have a size known at compile-time
+   |                            required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                          ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-dst-unsized.rs:17:28
+   |
+17 | const DST_UNSIZED: &[u8] = transmute_ref!(&[0u8; 1]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                                ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs
new file mode 100644
index 0000000..8dd191e
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.rs
@@ -0,0 +1,15 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+fn main() {}
+
+fn increase_lifetime() {
+    let x = 0u64;
+    // It is illegal to increase the lifetime scope.
+    let _: &'static u64 = zerocopy::transmute_ref!(&x);
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr
new file mode 100644
index 0000000..1ef34fe
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-illegal-lifetime.stderr
@@ -0,0 +1,12 @@
+error[E0597]: `x` does not live long enough
+  --> tests/ui-stable/transmute-ref-illegal-lifetime.rs:14:52
+   |
+12 |     let x = 0u64;
+   |         - binding `x` declared here
+13 |     // It is illegal to increase the lifetime scope.
+14 |     let _: &'static u64 = zerocopy::transmute_ref!(&x);
+   |            ------------                            ^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `x` is borrowed for `'static`
+15 | }
+   | - `x` dropped here while still borrowed
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs
new file mode 100644
index 0000000..1d66a54
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr
new file mode 100644
index 0000000..f353b26
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-size-decrease.rs:17:28
+   |
+17 | const DECREASE_SIZE: &u8 = transmute_ref!(&[0u8; 2]);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; 2]` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs
new file mode 100644
index 0000000..cdca560
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr
new file mode 100644
index 0000000..f51eb63
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-size-increase.rs:17:33
+   |
+17 | const INCREASE_SIZE: &[u8; 2] = transmute_ref!(&0u8);
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `[u8; 2]` (16 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs
new file mode 100644
index 0000000..409d785
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes, FromBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes, U: FromBytes>(t: &T) -> &U {
+    // `transmute_ref!` requires the source and destination types to be
+    // concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr
new file mode 100644
index 0000000..0905dc6
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `U` (this type does not have a fixed size)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-src-dst-generic.rs:18:5
+   |
+18 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, U>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs
new file mode 100644
index 0000000..114e917
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between non-reference source
+// and destination types.
+const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr
new file mode 100644
index 0000000..8a80e99
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-not-references.stderr
@@ -0,0 +1,45 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:54
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ---------------^^^^^^-
+   |                                       |              |
+   |                                       |              expected `&_`, found `usize`
+   |                                       expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
+help: consider borrowing here
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(&0usize);
+   |                                                      +
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-src-dst-not-references.rs:17:39
+   |
+17 | const SRC_DST_NOT_REFERENCES: usize = transmute_ref!(0usize);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `&_`
+   |
+   = note:   expected type `usize`
+           found reference `&_`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs
new file mode 100644
index 0000000..6bfe7ff
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting between unsized source and
+// destination types.
+const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr
new file mode 100644
index 0000000..7017c2f
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-dst-unsized.stderr
@@ -0,0 +1,183 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsFromBytes`
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsFromBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute`
+  --> $RUST/core/src/intrinsics.rs
+   |
+   |     pub fn transmute<Src, Dst>(src: Src) -> Dst;
+   |                           ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute`
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                doesn't have a size known at compile-time
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-dst-unsized.rs:17:32
+   |
+17 | const SRC_DST_UNSIZED: &[u8] = transmute_ref!(&[0u8][..]);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                                ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs
new file mode 100644
index 0000000..010281c
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::{transmute_ref, AsBytes};
+
+fn main() {}
+
+fn transmute_ref<T: AsBytes>(t: &T) -> &u8 {
+    // `transmute_ref!` requires the source type to be concrete.
+    transmute_ref!(t)
+}
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr
new file mode 100644
index 0000000..b6bbd16
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-generic.stderr
@@ -0,0 +1,19 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `T` (this type does not have a fixed size)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `$crate::assert_size_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-ref-src-generic.rs:17:5
+   |
+17 |     transmute_ref!(t)
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AlignOf<T>` (size can vary because of T)
+   = note: target type: `MaxAlignsOf<T, u8>` (size can vary because of T)
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs
new file mode 100644
index 0000000..90661b3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.rs
@@ -0,0 +1,17 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from a non-reference source
+// type.
+const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr
new file mode 100644
index 0000000..622c3db
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-a-reference.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> tests/ui-stable/transmute-ref-src-not-a-reference.rs:17:49
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(0usize);
+   |                                  ---------------^^^^^^-
+   |                                  |              |
+   |                                  |              expected `&_`, found `usize`
+   |                                  expected due to this
+   |
+   = note: expected reference `&_`
+                   found type `usize`
+help: consider borrowing here
+   |
+17 | const SRC_NOT_A_REFERENCE: &u8 = transmute_ref!(&0usize);
+   |                                                 +
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs
new file mode 100644
index 0000000..6ab19f3
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr
new file mode 100644
index 0000000..3b01fad
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                 |
+   |                                 the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |                                 required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-not-asbytes.rs:18:33
+   |
+18 | const SRC_NOT_AS_BYTES: &AU16 = transmute_ref!(&NotZerocopy(AU16(0)));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs
new file mode 100644
index 0000000..14e72b4
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+extern crate zerocopy;
+
+use zerocopy::transmute_ref;
+
+fn main() {}
+
+// `transmute_ref!` does not support transmuting from an unsized source type.
+const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr
new file mode 100644
index 0000000..73984d0
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-ref-src-unsized.stderr
@@ -0,0 +1,127 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               doesn't have a size known at compile-time
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `AlignOf::<T>::into_t`
+  --> src/macro_util.rs
+   |
+   | impl<T> AlignOf<T> {
+   |      ^ required by this bound in `AlignOf::<T>::into_t`
+   |     #[inline(never)] // Make `missing_inline_in_public_items` happy.
+   |     pub fn into_t(self) -> T {
+   |            ------ required by a bound in this associated function
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: the left-hand-side of an assignment must have a statically known size
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `MaxAlignsOf`
+  --> src/macro_util.rs
+   |
+   | pub union MaxAlignsOf<T, U> {
+   |                       ^ required by the implicit `Sized` requirement on this type parameter in `MaxAlignsOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `AlignOf`
+  --> src/macro_util.rs
+   |
+   | pub struct AlignOf<T> {
+   |                    ^ required by the implicit `Sized` requirement on this type parameter in `AlignOf`
+   = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> tests/ui-stable/transmute-ref-src-unsized.rs:16:31
+   |
+16 | const SRC_UNSIZED: &[u8; 1] = transmute_ref!(&[0u8][..]);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                               |
+   |                               doesn't have a size known at compile-time
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `transmute_ref`
+  --> src/macro_util.rs
+   |
+   | pub const unsafe fn transmute_ref<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
+   |                                                     ^^^ required by the implicit `Sized` requirement on this type parameter in `transmute_ref`
+   = note: this error originates in the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.rs
new file mode 100644
index 0000000..1d56831
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// Although this is not a soundness requirement, we currently require that the
+// size of the destination type is not smaller than the size of the source type.
+const DECREASE_SIZE: u8 = transmute!(AU16(0));
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.stderr
new file mode 100644
index 0000000..0241662
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-decrease.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-size-decrease.rs:19:27
+   |
+19 | const DECREASE_SIZE: u8 = transmute!(AU16(0));
+   |                           ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `AU16` (16 bits)
+   = note: target type: `u8` (8 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.rs
new file mode 100644
index 0000000..32f9363
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.rs
@@ -0,0 +1,19 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute!` does not support transmuting from a smaller type to a larger
+// one.
+const INCREASE_SIZE: AU16 = transmute!(0u8);
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.stderr
new file mode 100644
index 0000000..87d82a2
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-size-increase.stderr
@@ -0,0 +1,9 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> tests/ui-stable/transmute-size-increase.rs:19:29
+   |
+19 | const INCREASE_SIZE: AU16 = transmute!(0u8);
+   |                             ^^^^^^^^^^^^^^^
+   |
+   = note: source type: `u8` (8 bits)
+   = note: target type: `AU16` (16 bits)
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs
new file mode 100644
index 0000000..dd73021
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.rs
@@ -0,0 +1,18 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+include!("../../zerocopy-derive/tests/util.rs");
+
+extern crate zerocopy;
+
+use zerocopy::transmute;
+
+fn main() {}
+
+// `transmute` requires that the source type implements `AsBytes`
+const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
diff --git a/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr
new file mode 100644
index 0000000..836bf23
--- /dev/null
+++ b/extra_versions/crates/zerocopy/tests/ui-stable/transmute-src-not-asbytes.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                |
+   |                                the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |                                required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `NotZerocopy<AU16>: AsBytes` is not satisfied
+  --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy<AU16>`
+   |
+   = help: the following other types implement trait `AsBytes`:
+             ()
+             AU16
+             F32<O>
+             F64<O>
+             I128<O>
+             I16<O>
+             I32<O>
+             I64<O>
+           and $N others
+note: required by a bound in `AssertIsAsBytes`
+  --> tests/ui-stable/transmute-src-not-asbytes.rs:18:32
+   |
+18 | const SRC_NOT_AS_BYTES: AU16 = transmute!(NotZerocopy(AU16(0)));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertIsAsBytes`
+   = note: this error originates in the macro `transmute` (in Nightly builds, run with -Z macro-backtrace for more info)