chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "a6a530d0b09bb6218b8b1d7471ad0157096aeaee"
},
"path_in_vcs": "zerocopy-derive"
}

79
vendor/zerocopy-derive/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,79 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "dissimilar"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
[[package]]
name = "prettyplease"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2415488199887523e74fd9a5f7be804dfd42d868ae0eca382e3917094d210e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "zerocopy-derive"
version = "0.8.47"
dependencies = [
"dissimilar",
"prettyplease",
"proc-macro2",
"quote",
"rustversion",
"static_assertions",
"syn",
]

209
vendor/zerocopy-derive/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,209 @@
# 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 = "2021"
name = "zerocopy-derive"
version = "0.8.47"
authors = [
"Joshua Liebow-Feeser <joshlf@google.com>",
"Jack Wrenn <jswrenn@amazon.com>",
]
build = false
exclude = [
".*",
"tests/enum_from_bytes.rs",
"tests/ui-nightly/enum_from_bytes_u16_too_few.rs.disabled",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Custom derive for traits from the zerocopy crate"
readme = false
license = "BSD-2-Clause OR Apache-2.0 OR MIT"
repository = "https://github.com/google/zerocopy"
[lib]
name = "zerocopy_derive"
path = "src/lib.rs"
proc-macro = true
[[test]]
name = "deprecated"
path = "tests/deprecated.rs"
[[test]]
name = "enum_from_zeros"
path = "tests/enum_from_zeros.rs"
[[test]]
name = "enum_known_layout"
path = "tests/enum_known_layout.rs"
[[test]]
name = "enum_no_cell"
path = "tests/enum_no_cell.rs"
[[test]]
name = "enum_to_bytes"
path = "tests/enum_to_bytes.rs"
[[test]]
name = "enum_try_from_bytes"
path = "tests/enum_try_from_bytes.rs"
[[test]]
name = "enum_unaligned"
path = "tests/enum_unaligned.rs"
[[test]]
name = "eq"
path = "tests/eq.rs"
[[test]]
name = "hash"
path = "tests/hash.rs"
[[test]]
name = "hygiene"
path = "tests/hygiene.rs"
[[test]]
name = "include"
path = "tests/include.rs"
[[test]]
name = "issue_2117"
path = "tests/issue_2117.rs"
[[test]]
name = "issue_2835"
path = "tests/issue_2835.rs"
[[test]]
name = "issue_2880"
path = "tests/issue_2880.rs"
[[test]]
name = "issue_2915"
path = "tests/issue_2915.rs"
[[test]]
name = "on_error"
path = "tests/on_error.rs"
[[test]]
name = "paths_and_modules"
path = "tests/paths_and_modules.rs"
[[test]]
name = "priv_in_pub"
path = "tests/priv_in_pub.rs"
[[test]]
name = "struct_from_bytes"
path = "tests/struct_from_bytes.rs"
[[test]]
name = "struct_from_zeros"
path = "tests/struct_from_zeros.rs"
[[test]]
name = "struct_known_layout"
path = "tests/struct_known_layout.rs"
[[test]]
name = "struct_no_cell"
path = "tests/struct_no_cell.rs"
[[test]]
name = "struct_to_bytes"
path = "tests/struct_to_bytes.rs"
[[test]]
name = "struct_try_from_bytes"
path = "tests/struct_try_from_bytes.rs"
[[test]]
name = "struct_unaligned"
path = "tests/struct_unaligned.rs"
[[test]]
name = "ui"
path = "tests/ui.rs"
[[test]]
name = "union_from_bytes"
path = "tests/union_from_bytes.rs"
[[test]]
name = "union_from_zeros"
path = "tests/union_from_zeros.rs"
[[test]]
name = "union_known_layout"
path = "tests/union_known_layout.rs"
[[test]]
name = "union_no_cell"
path = "tests/union_no_cell.rs"
[[test]]
name = "union_to_bytes"
path = "tests/union_to_bytes.rs"
[[test]]
name = "union_try_from_bytes"
path = "tests/union_try_from_bytes.rs"
[[test]]
name = "union_unaligned"
path = "tests/union_unaligned.rs"
[[test]]
name = "unsafe_cell"
path = "tests/unsafe_cell.rs"
[dependencies.proc-macro2]
version = "1.0.1"
[dependencies.quote]
version = "1.0.40"
[dependencies.syn]
version = "2.0.46"
features = ["full"]
[dev-dependencies.dissimilar]
version = "1.0.9"
[dev-dependencies.prettyplease]
version = "=0.2.17"
[dev-dependencies.rustversion]
version = "1.0"
[dev-dependencies.static_assertions]
version = "1.1"
[dev-dependencies.syn]
version = "2.0.46"
features = ["visit"]
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = [
"cfg(zerocopy_derive_union_into_bytes)",
"cfg(zerocopy_unstable_derive_on_error)",
]

202
vendor/zerocopy-derive/LICENSE-APACHE vendored Normal file
View File

@@ -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.

24
vendor/zerocopy-derive/LICENSE-BSD vendored Normal file
View File

@@ -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.

26
vendor/zerocopy-derive/LICENSE-MIT vendored Normal file
View File

@@ -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.

View File

@@ -0,0 +1,190 @@
use proc_macro2::{Span, TokenStream};
use syn::{
parse_quote, Data, DataEnum, DataStruct, DataUnion, Error, Expr, ExprLit, ExprUnary, Lit, UnOp,
WherePredicate,
};
use crate::{
derive::try_from_bytes::derive_try_from_bytes,
repr::{CompoundRepr, EnumRepr, Repr, Spanned},
util::{enum_size_from_repr, Ctx, FieldBounds, ImplBlockBuilder, Trait, TraitBound},
};
/// Returns `Ok(index)` if variant `index` of the enum has a discriminant of
/// zero. If `Err(bool)` is returned, the boolean is true if the enum has
/// unknown discriminants (e.g. discriminants set to const expressions which we
/// can't evaluate in a proc macro). If the enum has unknown discriminants, then
/// it might have a zero variant that we just can't detect.
pub(crate) fn find_zero_variant(enm: &DataEnum) -> Result<usize, bool> {
// Discriminants can be anywhere in the range [i128::MIN, u128::MAX] because
// the discriminant type may be signed or unsigned. Since we only care about
// tracking the discriminant when it's less than or equal to zero, we can
// avoid u128 -> i128 conversions and bounds checking by making the "next
// discriminant" value implicitly negative.
// Technically 64 bits is enough, but 128 is better for future compatibility
// with https://github.com/rust-lang/rust/issues/56071
let mut next_negative_discriminant = Some(0);
// Sometimes we encounter explicit discriminants that we can't know the
// value of (e.g. a constant expression that requires evaluation). These
// could evaluate to zero or a negative number, but we can't assume that
// they do (no false positives allowed!). So we treat them like strictly-
// positive values that can't result in any zero variants, and track whether
// we've encountered any unknown discriminants.
let mut has_unknown_discriminants = false;
for (i, v) in enm.variants.iter().enumerate() {
match v.discriminant.as_ref() {
// Implicit discriminant
None => {
match next_negative_discriminant.as_mut() {
Some(0) => return Ok(i),
// n is nonzero so subtraction is always safe
Some(n) => *n -= 1,
None => (),
}
}
// Explicit positive discriminant
Some((_, Expr::Lit(ExprLit { lit: Lit::Int(int), .. }))) => {
match int.base10_parse::<u128>().ok() {
Some(0) => return Ok(i),
Some(_) => next_negative_discriminant = None,
None => {
// Numbers should never fail to parse, but just in case:
has_unknown_discriminants = true;
next_negative_discriminant = None;
}
}
}
// Explicit negative discriminant
Some((_, Expr::Unary(ExprUnary { op: UnOp::Neg(_), expr, .. }))) => match &**expr {
Expr::Lit(ExprLit { lit: Lit::Int(int), .. }) => {
match int.base10_parse::<u128>().ok() {
Some(0) => return Ok(i),
// x is nonzero so subtraction is always safe
Some(x) => next_negative_discriminant = Some(x - 1),
None => {
// Numbers should never fail to parse, but just in
// case:
has_unknown_discriminants = true;
next_negative_discriminant = None;
}
}
}
// Unknown negative discriminant (e.g. const repr)
_ => {
has_unknown_discriminants = true;
next_negative_discriminant = None;
}
},
// Unknown discriminant (e.g. const expr)
_ => {
has_unknown_discriminants = true;
next_negative_discriminant = None;
}
}
}
Err(has_unknown_discriminants)
}
pub(crate) fn derive_from_zeros(ctx: &Ctx, top_level: Trait) -> Result<TokenStream, Error> {
let try_from_bytes = derive_try_from_bytes(ctx, top_level)?;
let from_zeros = match &ctx.ast.data {
Data::Struct(strct) => derive_from_zeros_struct(ctx, strct),
Data::Enum(enm) => derive_from_zeros_enum(ctx, enm)?,
Data::Union(unn) => derive_from_zeros_union(ctx, unn),
};
Ok(IntoIterator::into_iter([try_from_bytes, from_zeros]).collect())
}
pub(crate) fn derive_from_bytes(ctx: &Ctx, top_level: Trait) -> Result<TokenStream, Error> {
let from_zeros = derive_from_zeros(ctx, top_level)?;
let from_bytes = match &ctx.ast.data {
Data::Struct(strct) => derive_from_bytes_struct(ctx, strct),
Data::Enum(enm) => derive_from_bytes_enum(ctx, enm)?,
Data::Union(unn) => derive_from_bytes_union(ctx, unn),
};
Ok(IntoIterator::into_iter([from_zeros, from_bytes]).collect())
}
fn derive_from_zeros_struct(ctx: &Ctx, strct: &DataStruct) -> TokenStream {
ImplBlockBuilder::new(ctx, strct, Trait::FromZeros, FieldBounds::ALL_SELF).build()
}
fn derive_from_zeros_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> {
let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
// We don't actually care what the repr is; we just care that it's one of
// the allowed ones.
match repr {
Repr::Compound(Spanned { t: CompoundRepr::C | CompoundRepr::Primitive(_), span: _ }, _) => {
}
Repr::Transparent(_) | Repr::Compound(Spanned { t: CompoundRepr::Rust, span: _ }, _) => {
return ctx.error_or_skip(
Error::new(
Span::call_site(),
"must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout",
),
);
}
}
let zero_variant = match find_zero_variant(enm) {
Ok(index) => enm.variants.iter().nth(index).unwrap(),
// Has unknown variants
Err(true) => {
return ctx.error_or_skip(Error::new_spanned(
&ctx.ast,
"FromZeros only supported on enums with a variant that has a discriminant of `0`\n\
help: This enum has discriminants which are not literal integers. One of those may \
define or imply which variant has a discriminant of zero. Use a literal integer to \
define or imply the variant with a discriminant of zero.",
));
}
// Does not have unknown variants
Err(false) => {
return ctx.error_or_skip(Error::new_spanned(
&ctx.ast,
"FromZeros only supported on enums with a variant that has a discriminant of `0`",
));
}
};
let zerocopy_crate = &ctx.zerocopy_crate;
let explicit_bounds = zero_variant
.fields
.iter()
.map(|field| {
let ty = &field.ty;
parse_quote! { #ty: #zerocopy_crate::FromZeros }
})
.collect::<Vec<WherePredicate>>();
Ok(ImplBlockBuilder::new(ctx, enm, Trait::FromZeros, FieldBounds::Explicit(explicit_bounds))
.build())
}
fn derive_from_zeros_union(ctx: &Ctx, unn: &DataUnion) -> TokenStream {
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
ImplBlockBuilder::new(ctx, unn, Trait::FromZeros, field_type_trait_bounds).build()
}
fn derive_from_bytes_struct(ctx: &Ctx, strct: &DataStruct) -> TokenStream {
ImplBlockBuilder::new(ctx, strct, Trait::FromBytes, FieldBounds::ALL_SELF).build()
}
fn derive_from_bytes_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> {
let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
let variants_required = 1usize << enum_size_from_repr(&repr)?;
if enm.variants.len() != variants_required {
return ctx.error_or_skip(Error::new_spanned(
&ctx.ast,
format!(
"FromBytes only supported on {} enum with {} variants",
repr.repr_type_name(),
variants_required
),
));
}
Ok(ImplBlockBuilder::new(ctx, enm, Trait::FromBytes, FieldBounds::ALL_SELF).build())
}
fn derive_from_bytes_union(ctx: &Ctx, unn: &DataUnion) -> TokenStream {
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
ImplBlockBuilder::new(ctx, unn, Trait::FromBytes, field_type_trait_bounds).build()
}

View File

@@ -0,0 +1,162 @@
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, DataEnum, DataStruct, DataUnion, Error, Type};
use crate::{
repr::{EnumRepr, StructUnionRepr},
util::{
generate_tag_enum, Ctx, DataExt, FieldBounds, ImplBlockBuilder, PaddingCheck, Trait,
TraitBound,
},
};
pub(crate) fn derive_into_bytes(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
match &ctx.ast.data {
Data::Struct(strct) => derive_into_bytes_struct(ctx, strct),
Data::Enum(enm) => derive_into_bytes_enum(ctx, enm),
Data::Union(unn) => derive_into_bytes_union(ctx, unn),
}
}
fn derive_into_bytes_struct(ctx: &Ctx, strct: &DataStruct) -> Result<TokenStream, Error> {
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
let is_transparent = repr.is_transparent();
let is_c = repr.is_c();
let is_packed_1 = repr.is_packed_1();
let num_fields = strct.fields().len();
let (padding_check, require_unaligned_fields) = if is_transparent || is_packed_1 {
// No padding check needed.
// - 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 `IntoBytes` (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 `IntoBytes` (meaning they don't have any
// padding). Note that this holds regardless of other `repr`
// attributes, including `repr(Rust)`. [1]
//
// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#the-alignment-modifiers:
//
// An important consequence of these rules is that a type with
// `#[repr(packed(1))]`` (or `#[repr(packed)]``) will have no
// inter-field padding.
(None, false)
} else if is_c && !repr.is_align_gt_1() && num_fields <= 1 {
// No padding check needed. A repr(C) struct with zero or one field has
// no padding unless #[repr(align)] explicitly adds padding, which we
// check for in this branch's condition.
(None, false)
} else if ctx.ast.generics.params.is_empty() {
// Is the last field a syntactic slice, i.e., `[SomeType]`.
let is_syntactic_dst =
strct.fields().last().map(|(_, _, ty)| matches!(ty, Type::Slice(_))).unwrap_or(false);
// Since there are no generics, we can emit a padding check. All reprs
// guarantee that fields won't overlap [1], so the padding check is
// sound. This is more permissive than the next case, which requires
// that all field types implement `Unaligned`.
//
// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#the-rust-representation:
//
// The only data layout guarantees made by [`repr(Rust)`] are those
// required for soundness. They are:
// ...
// 2. The fields do not overlap.
// ...
if is_c && is_syntactic_dst {
(Some(PaddingCheck::ReprCStruct), false)
} else {
(Some(PaddingCheck::Struct), false)
}
} else if is_c && !repr.is_align_gt_1() {
// We can't use a padding check since there are generic type arguments.
// Instead, we require all field types to implement `Unaligned`. This
// ensures that the `repr(C)` layout algorithm will not insert any
// padding unless #[repr(align)] explicitly adds padding, which we check
// for in this branch's condition.
//
// FIXME(#10): Support type parameters for non-transparent, non-packed
// structs without requiring `Unaligned`.
(None, true)
} else {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must have a non-align #[repr(...)] attribute in order to guarantee this type's memory layout",
));
};
let field_bounds = if require_unaligned_fields {
FieldBounds::All(&[TraitBound::Slf, TraitBound::Other(Trait::Unaligned)])
} else {
FieldBounds::ALL_SELF
};
Ok(ImplBlockBuilder::new(ctx, strct, Trait::IntoBytes, field_bounds)
.padding_check(padding_check)
.build())
}
fn derive_into_bytes_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> {
let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
if !repr.is_c() && !repr.is_primitive() {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout",
));
}
let tag_type_definition = generate_tag_enum(ctx, &repr, enm);
Ok(ImplBlockBuilder::new(ctx, enm, Trait::IntoBytes, FieldBounds::ALL_SELF)
.padding_check(PaddingCheck::Enum { tag_type_definition })
.build())
}
fn derive_into_bytes_union(ctx: &Ctx, unn: &DataUnion) -> Result<TokenStream, Error> {
// See #1792 for more context.
//
// By checking for `zerocopy_derive_union_into_bytes` both here and in the
// generated code, we ensure that `--cfg zerocopy_derive_union_into_bytes`
// need only be passed *either* when compiling this crate *or* when
// compiling the user's crate. The former is preferable, but in some
// situations (such as when cross-compiling using `cargo build --target`),
// it doesn't get propagated to this crate's build by default.
let cfg_compile_error = if cfg!(zerocopy_derive_union_into_bytes) {
quote!()
} else {
let core = ctx.core_path();
let error_message = "requires --cfg zerocopy_derive_union_into_bytes;
please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802";
quote!(
#[allow(unused_attributes, unexpected_cfgs)]
const _: () = {
#[cfg(not(zerocopy_derive_union_into_bytes))]
#core::compile_error!(#error_message);
};
)
};
// FIXME(#10): Support type parameters.
if !ctx.ast.generics.params.is_empty() {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"unsupported on types with type parameters",
));
}
// Because we don't support generics, we don't need to worry about
// special-casing different reprs. So long as there is *some* repr which
// guarantees the layout, our `PaddingCheck::Union` guarantees that there is
// no padding.
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
if !repr.is_c() && !repr.is_transparent() && !repr.is_packed_1() {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must be #[repr(C)], #[repr(packed)], or #[repr(transparent)]",
));
}
let impl_block = ImplBlockBuilder::new(ctx, unn, Trait::IntoBytes, FieldBounds::ALL_SELF)
.padding_check(PaddingCheck::Union)
.build();
Ok(quote!(#cfg_compile_error #impl_block))
}

View File

@@ -0,0 +1,348 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse_quote, Data, Error, Type};
use crate::{
repr::StructUnionRepr,
util::{Ctx, DataExt, FieldBounds, ImplBlockBuilder, SelfBounds, Trait},
};
fn derive_known_layout_for_repr_c_struct<'a>(
ctx: &'a Ctx,
repr: &StructUnionRepr,
fields: &[(&'a syn::Visibility, TokenStream, &'a Type)],
) -> Option<(SelfBounds<'a>, TokenStream, Option<TokenStream>)> {
let (trailing_field, leading_fields) = fields.split_last()?;
let (_vis, trailing_field_name, trailing_field_ty) = trailing_field;
let leading_fields_tys = leading_fields.iter().map(|(_vis, _name, ty)| ty);
let core = ctx.core_path();
let repr_align = repr
.get_align()
.map(|align| {
let align = align.t.get();
quote!(#core::num::NonZeroUsize::new(#align as usize))
})
.unwrap_or_else(|| quote!(#core::option::Option::None));
let repr_packed = repr
.get_packed()
.map(|packed| {
let packed = packed.get();
quote!(#core::num::NonZeroUsize::new(#packed as usize))
})
.unwrap_or_else(|| quote!(#core::option::Option::None));
let zerocopy_crate = &ctx.zerocopy_crate;
let make_methods = |trailing_field_ty| {
quote! {
// SAFETY:
// - The returned pointer has the same address and provenance as
// `bytes`:
// - 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.
// - If `Self` is a slice DST, the returned pointer encodes
// `elems` elements in the trailing slice:
// - This is true of the recursive call to `raw_from_ptr_len`.
// - `trailing.as_ptr() as *mut Self` preserves trailing slice
// element count [1].
// - `NonNull::new_unchecked` preserves trailing slice element
// count.
//
// [1] Per https://doc.rust-lang.org/reference/expressions/operator-expr.html#pointer-to-pointer-cast:
//
// `*const T`` / `*mut T` can be cast to `*const U` / `*mut U`
// with the following behavior:
// ...
// - If `T` and `U` are both unsized, the pointer is also
// returned unchanged. In particular, the metadata is
// preserved exactly.
//
// For instance, a cast from `*const [T]` to `*const [U]`
// preserves the number of elements. ... 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)`.
#[inline(always)]
fn raw_from_ptr_len(
bytes: #core::ptr::NonNull<u8>,
meta: <Self as #zerocopy_crate::KnownLayout>::PointerMetadata,
) -> #core::ptr::NonNull<Self> {
let trailing = <#trailing_field_ty as #zerocopy_crate::KnownLayout>::raw_from_ptr_len(bytes, meta);
let slf = trailing.as_ptr() as *mut Self;
// SAFETY: Constructed from `trailing`, which is non-null.
unsafe { #core::ptr::NonNull::new_unchecked(slf) }
}
#[inline(always)]
fn pointer_to_metadata(ptr: *mut Self) -> <Self as #zerocopy_crate::KnownLayout>::PointerMetadata {
<#trailing_field_ty>::pointer_to_metadata(ptr as *mut _)
}
}
};
let inner_extras = {
let leading_fields_tys = leading_fields_tys.clone();
let methods = make_methods(*trailing_field_ty);
let (_, ty_generics, _) = ctx.ast.generics.split_for_impl();
quote!(
type PointerMetadata = <#trailing_field_ty as #zerocopy_crate::KnownLayout>::PointerMetadata;
type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit #ty_generics;
// SAFETY: `LAYOUT` accurately describes the layout of `Self`.
// The documentation of `DstLayout::for_repr_c_struct` vows that
// invocations in this manner will accurately 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_crate::DstLayout = #zerocopy_crate::DstLayout::for_repr_c_struct(
#repr_align,
#repr_packed,
&[
#(#zerocopy_crate::DstLayout::for_type::<#leading_fields_tys>(),)*
<#trailing_field_ty as #zerocopy_crate::KnownLayout>::LAYOUT
],
);
#methods
)
};
let outer_extras = {
let ident = &ctx.ast.ident;
let vis = &ctx.ast.vis;
let params = &ctx.ast.generics.params;
let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
let predicates = if let Some(where_clause) = where_clause {
where_clause.predicates.clone()
} else {
Default::default()
};
// Generate a valid ident for a type-level handle to a field of a
// given `name`.
let field_index = |name: &TokenStream| ident!(("__Zerocopy_Field_{}", name), ident.span());
let field_indices: Vec<_> =
fields.iter().map(|(_vis, name, _ty)| field_index(name)).collect();
// Define the collection of type-level field handles.
let field_defs = field_indices.iter().zip(fields).map(|(idx, (vis, _, _))| {
quote! {
#vis struct #idx;
}
});
let field_impls = field_indices.iter().zip(fields).map(|(idx, (_, _, ty))| quote! {
// SAFETY: `#ty` is the type of `#ident`'s field at `#idx`.
//
// We implement `Field` for each field of the struct to create a
// projection from the field index to its type. This allows us
// to refer to the field's type in a way that respects `Self`
// hygiene. If we just copy-pasted the tokens of `#ty`, we
// would not respect `Self` hygiene, as `Self` would refer to
// the helper struct we are generating, not the derive target
// type.
unsafe impl #impl_generics #zerocopy_crate::util::macro_util::Field<#idx> for #ident #ty_generics
where
#predicates
{
type Type = #ty;
}
});
let trailing_field_index = field_index(trailing_field_name);
let leading_field_indices =
leading_fields.iter().map(|(_vis, name, _ty)| field_index(name));
// We use `Field` to project the type of the trailing field. This is
// required to ensure that if the field type uses `Self`, it
// resolves to the derive target type, not the helper struct we are
// generating.
let trailing_field_ty = quote! {
<#ident #ty_generics as
#zerocopy_crate::util::macro_util::Field<#trailing_field_index>
>::Type
};
let methods = make_methods(&parse_quote! {
<#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
});
let core = ctx.core_path();
quote! {
#(#field_defs)*
#(#field_impls)*
// SAFETY: This has the same layout as the derive target type,
// except that it admits uninit bytes. This is ensured by using
// the same repr as the target type, and by using field types
// which have the same layout as the target type's fields,
// except that they admit uninit bytes. We indirect through
// `Field` to ensure that occurrences of `Self` resolve to
// `#ty`, not `__ZerocopyKnownLayoutMaybeUninit` (see #2116).
#repr
#[doc(hidden)]
#vis struct __ZerocopyKnownLayoutMaybeUninit<#params> (
#(#core::mem::MaybeUninit<
<#ident #ty_generics as
#zerocopy_crate::util::macro_util::Field<#leading_field_indices>
>::Type
>,)*
// NOTE(#2302): We wrap in `ManuallyDrop` here in case the
// type we're operating on is both generic and
// `repr(packed)`. In that case, Rust needs to know that the
// type is *either* `Sized` or has a trivial `Drop`.
// `ManuallyDrop` has a trivial `Drop`, and so satisfies
// this requirement.
#core::mem::ManuallyDrop<
<#trailing_field_ty as #zerocopy_crate::KnownLayout>::MaybeUninit
>
)
where
#trailing_field_ty: #zerocopy_crate::KnownLayout,
#predicates;
// SAFETY: We largely defer to the `KnownLayout` implementation
// on the derive target type (both by using the same tokens, and
// by deferring to impl via type-level indirection). This is
// sound, since `__ZerocopyKnownLayoutMaybeUninit` is guaranteed
// to have the same layout as the derive target type, except
// that `__ZerocopyKnownLayoutMaybeUninit` admits uninit bytes.
unsafe impl #impl_generics #zerocopy_crate::KnownLayout for __ZerocopyKnownLayoutMaybeUninit #ty_generics
where
#trailing_field_ty: #zerocopy_crate::KnownLayout,
#predicates
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::PointerMetadata;
type MaybeUninit = Self;
const LAYOUT: #zerocopy_crate::DstLayout = <#ident #ty_generics as #zerocopy_crate::KnownLayout>::LAYOUT;
#methods
}
}
};
Some((SelfBounds::None, inner_extras, Some(outer_extras)))
}
pub(crate) fn derive(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
// If this is a `repr(C)` struct, then `c_struct_repr` contains the entire
// `repr` attribute.
let c_struct_repr = match &ctx.ast.data {
Data::Struct(..) => {
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
if repr.is_c() {
Some(repr)
} else {
None
}
}
Data::Enum(..) | Data::Union(..) => None,
};
let fields = ctx.ast.data.fields();
let (self_bounds, inner_extras, outer_extras) = c_struct_repr
.as_ref()
.and_then(|repr| {
derive_known_layout_for_repr_c_struct(ctx, repr, &fields)
})
.unwrap_or_else(|| {
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
// 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.
(
SelfBounds::SIZED,
quote!(
type PointerMetadata = ();
type MaybeUninit =
#core::mem::MaybeUninit<Self>;
// 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_crate::DstLayout = #zerocopy_crate::DstLayout::for_type::<Self>();
// SAFETY: `.cast` preserves address and provenance.
//
// FIXME(#429): Add documentation to `.cast` that promises that
// it preserves provenance.
#[inline(always)]
fn raw_from_ptr_len(bytes: #core::ptr::NonNull<u8>, _meta: ()) -> #core::ptr::NonNull<Self> {
bytes.cast::<Self>()
}
#[inline(always)]
fn pointer_to_metadata(_ptr: *mut Self) -> () {}
),
None,
)
});
Ok(match &ctx.ast.data {
Data::Struct(strct) => {
let require_trait_bound_on_field_types =
if matches!(self_bounds, SelfBounds::All(&[Trait::Sized])) {
FieldBounds::None
} else {
FieldBounds::TRAILING_SELF
};
// 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`.
ImplBlockBuilder::new(
ctx,
strct,
Trait::KnownLayout,
require_trait_bound_on_field_types,
)
.self_type_trait_bounds(self_bounds)
.inner_extras(inner_extras)
.outer_extras(outer_extras)
.build()
}
Data::Enum(enm) => {
// A bound on the trailing field is not required, since enums cannot
// currently be unsized.
ImplBlockBuilder::new(ctx, enm, Trait::KnownLayout, FieldBounds::None)
.self_type_trait_bounds(SelfBounds::SIZED)
.inner_extras(inner_extras)
.outer_extras(outer_extras)
.build()
}
Data::Union(unn) => {
// A bound on the trailing field is not required, since unions
// cannot currently be unsized.
ImplBlockBuilder::new(ctx, unn, Trait::KnownLayout, FieldBounds::None)
.self_type_trait_bounds(SelfBounds::SIZED)
.inner_extras(inner_extras)
.outer_extras(outer_extras)
.build()
}
})
}

130
vendor/zerocopy-derive/src/derive/mod.rs vendored Normal file
View File

@@ -0,0 +1,130 @@
pub mod from_bytes;
pub mod into_bytes;
pub mod known_layout;
pub mod try_from_bytes;
pub mod unaligned;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Data, Error};
use crate::{
repr::StructUnionRepr,
util::{Ctx, DataExt, FieldBounds, ImplBlockBuilder, Trait},
};
pub(crate) fn derive_immutable(ctx: &Ctx, _top_level: Trait) -> TokenStream {
match &ctx.ast.data {
Data::Struct(strct) => {
ImplBlockBuilder::new(ctx, strct, Trait::Immutable, FieldBounds::ALL_SELF).build()
}
Data::Enum(enm) => {
ImplBlockBuilder::new(ctx, enm, Trait::Immutable, FieldBounds::ALL_SELF).build()
}
Data::Union(unn) => {
ImplBlockBuilder::new(ctx, unn, Trait::Immutable, FieldBounds::ALL_SELF).build()
}
}
}
pub(crate) fn derive_hash(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
// This doesn't delegate to `impl_block` because `impl_block` assumes it is
// deriving a `zerocopy`-defined trait, and these trait impls share a common
// shape that `Hash` does not. In particular, `zerocopy` traits contain a
// method that only `zerocopy_derive` macros are supposed to implement, and
// `impl_block` generating this trait method is incompatible with `Hash`.
let type_ident = &ctx.ast.ident;
let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
let where_predicates = where_clause.map(|clause| &clause.predicates);
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
Ok(quote! {
impl #impl_generics #core::hash::Hash for #type_ident #ty_generics
where
Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
#where_predicates
{
fn hash<H: #core::hash::Hasher>(&self, state: &mut H) {
#core::hash::Hasher::write(state, #zerocopy_crate::IntoBytes::as_bytes(self))
}
fn hash_slice<H: #core::hash::Hasher>(data: &[Self], state: &mut H) {
#core::hash::Hasher::write(state, #zerocopy_crate::IntoBytes::as_bytes(data))
}
}
})
}
pub(crate) fn derive_eq(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
// This doesn't delegate to `impl_block` because `impl_block` assumes it is
// deriving a `zerocopy`-defined trait, and these trait impls share a common
// shape that `Eq` does not. In particular, `zerocopy` traits contain a
// method that only `zerocopy_derive` macros are supposed to implement, and
// `impl_block` generating this trait method is incompatible with `Eq`.
let type_ident = &ctx.ast.ident;
let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
let where_predicates = where_clause.map(|clause| &clause.predicates);
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
Ok(quote! {
impl #impl_generics #core::cmp::PartialEq for #type_ident #ty_generics
where
Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
#where_predicates
{
fn eq(&self, other: &Self) -> bool {
#core::cmp::PartialEq::eq(
#zerocopy_crate::IntoBytes::as_bytes(self),
#zerocopy_crate::IntoBytes::as_bytes(other),
)
}
}
impl #impl_generics #core::cmp::Eq for #type_ident #ty_generics
where
Self: #zerocopy_crate::IntoBytes + #zerocopy_crate::Immutable,
#where_predicates
{
}
})
}
pub(crate) fn derive_split_at(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
match &ctx.ast.data {
Data::Struct(_) => {}
Data::Enum(_) | Data::Union(_) => {
return Err(Error::new(Span::call_site(), "can only be applied to structs"));
}
};
if repr.get_packed().is_some() {
return Err(Error::new(Span::call_site(), "must not have #[repr(packed)] attribute"));
}
if !(repr.is_c() || repr.is_transparent()) {
return Err(Error::new(
Span::call_site(),
"must have #[repr(C)] or #[repr(transparent)] in order to guarantee this type's layout is splitable",
));
}
let fields = ctx.ast.data.fields();
let trailing_field = if let Some(((_, _, trailing_field), _)) = fields.split_last() {
trailing_field
} else {
return Err(Error::new(Span::call_site(), "must at least one field"));
};
let zerocopy_crate = &ctx.zerocopy_crate;
// SAFETY: `#ty`, per the above checks, is `repr(C)` or `repr(transparent)`
// and is not packed; its trailing field is guaranteed to be well-aligned
// for its type. By invariant on `FieldBounds::TRAILING_SELF`, the trailing
// slice of the trailing field is also well-aligned for its type.
Ok(ImplBlockBuilder::new(ctx, &ctx.ast.data, Trait::SplitAt, FieldBounds::TRAILING_SELF)
.inner_extras(quote! {
type Elem = <#trailing_field as #zerocopy_crate::SplitAt>::Elem;
})
.build())
}

View File

@@ -0,0 +1,763 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{
parse_quote, spanned::Spanned as _, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error,
Expr, Fields, Ident, Index, Type,
};
use crate::{
repr::{EnumRepr, StructUnionRepr},
util::{
const_block, enum_size_from_repr, generate_tag_enum, Ctx, DataExt, FieldBounds,
ImplBlockBuilder, Trait, TraitBound,
},
};
fn tag_ident(variant_ident: &Ident) -> Ident {
ident!(("___ZEROCOPY_TAG_{}", variant_ident), variant_ident.span())
}
/// Generates a constant for the tag associated with each variant of the enum.
/// When we match on the enum's tag, each arm matches one of these constants. We
/// have to use constants here because:
///
/// - The type that we're matching on is not the type of the tag, it's an
/// integer of the same size as the tag type and with the same bit patterns.
/// - We can't read the enum tag as an enum because the bytes may not represent
/// a valid variant.
/// - Patterns do not currently support const expressions, so we have to assign
/// these constants to names rather than use them inline in the `match`
/// statement.
fn generate_tag_consts(data: &DataEnum) -> TokenStream {
let tags = data.variants.iter().map(|v| {
let variant_ident = &v.ident;
let tag_ident = tag_ident(variant_ident);
quote! {
// This casts the enum variant to its discriminant, and then
// converts the discriminant to the target integral type via a
// numeric cast [1].
//
// Because these are the same size, this is defined to be a no-op
// and therefore is a lossless conversion [2].
//
// [1] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#enum-cast:
//
// Casts an enum to its discriminant.
//
// [2] Per https://doc.rust-lang.org/1.81.0/reference/expressions/operator-expr.html#numeric-cast:
//
// Casting between two integers of the same size (e.g. i32 -> u32)
// is a no-op.
const #tag_ident: ___ZerocopyTagPrimitive =
___ZerocopyTag::#variant_ident as ___ZerocopyTagPrimitive;
}
});
quote! {
#(#tags)*
}
}
fn variant_struct_ident(variant_ident: &Ident) -> Ident {
ident!(("___ZerocopyVariantStruct_{}", variant_ident), variant_ident.span())
}
/// Generates variant structs for the given enum variant.
///
/// These are structs associated with each variant of an enum. They are
/// `repr(C)` tuple structs with the same fields as the variant after a
/// `MaybeUninit<___ZerocopyInnerTag>`.
///
/// In order to unify the generated types for `repr(C)` and `repr(int)` enums,
/// we use a "fused" representation with fields for both an inner tag and an
/// outer tag. Depending on the repr, we will set one of these tags to the tag
/// type and the other to `()`. This lets us generate the same code but put the
/// tags in different locations.
fn generate_variant_structs(ctx: &Ctx, data: &DataEnum) -> TokenStream {
let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
let enum_name = &ctx.ast.ident;
// All variant structs have a `PhantomData<MyEnum<...>>` field because we
// don't know which generic parameters each variant will use, and unused
// generic parameters are a compile error.
let core = ctx.core_path();
let phantom_ty = quote! {
#core::marker::PhantomData<#enum_name #ty_generics>
};
let variant_structs = data.variants.iter().filter_map(|variant| {
// We don't generate variant structs for unit variants because we only
// need to check the tag. This helps cut down our generated code a bit.
if matches!(variant.fields, Fields::Unit) {
return None;
}
let variant_struct_ident = variant_struct_ident(&variant.ident);
let field_types = variant.fields.iter().map(|f| &f.ty);
let variant_struct = parse_quote! {
#[repr(C)]
struct #variant_struct_ident #impl_generics (
#core::mem::MaybeUninit<___ZerocopyInnerTag>,
#(#field_types,)*
#phantom_ty,
) #where_clause;
};
// We do this rather than emitting `#[derive(::zerocopy::TryFromBytes)]`
// because that is not hygienic, and this is also more performant.
let try_from_bytes_impl =
derive_try_from_bytes(&ctx.with_input(&variant_struct), Trait::TryFromBytes)
.expect("derive_try_from_bytes should not fail on synthesized type");
Some(quote! {
#variant_struct
#try_from_bytes_impl
})
});
quote! {
#(#variant_structs)*
}
}
fn variants_union_field_ident(ident: &Ident) -> Ident {
// Field names are prefixed with `__field_` to prevent name collision
// with the `__nonempty` field.
ident!(("__field_{}", ident), ident.span())
}
fn generate_variants_union(ctx: &Ctx, data: &DataEnum) -> TokenStream {
let generics = &ctx.ast.generics;
let (_, ty_generics, _) = generics.split_for_impl();
let fields = data.variants.iter().filter_map(|variant| {
// We don't generate variant structs for unit variants because we only
// need to check the tag. This helps cut down our generated code a bit.
if matches!(variant.fields, Fields::Unit) {
return None;
}
let field_name = variants_union_field_ident(&variant.ident);
let variant_struct_ident = variant_struct_ident(&variant.ident);
let core = ctx.core_path();
Some(quote! {
#field_name: #core::mem::ManuallyDrop<#variant_struct_ident #ty_generics>,
})
});
let variants_union = parse_quote! {
#[repr(C)]
union ___ZerocopyVariants #generics {
#(#fields)*
// Enums can have variants with no fields, but unions must
// have at least one field. So we just add a trailing unit
// to ensure that this union always has at least one field.
// Because this union is `repr(C)`, this unit type does not
// affect the layout.
__nonempty: (),
}
};
let has_field =
derive_has_field_struct_union(&ctx.with_input(&variants_union), &variants_union.data);
quote! {
#variants_union
#has_field
}
}
/// Generates an implementation of `is_bit_valid` for an arbitrary enum.
///
/// The general process is:
///
/// 1. Generate a tag enum. This is an enum with the same repr, variants, and
/// corresponding discriminants as the original enum, but without any fields
/// on the variants. This gives us access to an enum where the variants have
/// the same discriminants as the one we're writing `is_bit_valid` for.
/// 2. Make constants from the variants of the tag enum. We need these because
/// we can't put const exprs in match arms.
/// 3. Generate variant structs. These are structs which have the same fields as
/// each variant of the enum, and are `#[repr(C)]` with an optional "inner
/// tag".
/// 4. Generate a variants union, with one field for each variant struct type.
/// 5. And finally, our raw enum is a `#[repr(C)]` struct of an "outer tag" and
/// the variants union.
///
/// See these reference links for fully-worked example decompositions.
///
/// - `repr(C)`: <https://doc.rust-lang.org/reference/type-layout.html#reprc-enums-with-fields>
/// - `repr(int)`: <https://doc.rust-lang.org/reference/type-layout.html#primitive-representation-of-enums-with-fields>
/// - `repr(C, int)`: <https://doc.rust-lang.org/reference/type-layout.html#combining-primitive-representations-of-enums-with-fields-and-reprc>
pub(crate) fn derive_is_bit_valid(
ctx: &Ctx,
data: &DataEnum,
repr: &EnumRepr,
) -> Result<TokenStream, Error> {
let trait_path = Trait::TryFromBytes.crate_path(ctx);
let tag_enum = generate_tag_enum(ctx, repr, data);
let tag_consts = generate_tag_consts(data);
let (outer_tag_type, inner_tag_type) = if repr.is_c() {
(quote! { ___ZerocopyTag }, quote! { () })
} else if repr.is_primitive() {
(quote! { () }, quote! { ___ZerocopyTag })
} else {
return Err(Error::new(
ctx.ast.span(),
"must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout",
));
};
let variant_structs = generate_variant_structs(ctx, data);
let variants_union = generate_variants_union(ctx, data);
let (impl_generics, ty_generics, where_clause) = ctx.ast.generics.split_for_impl();
let zerocopy_crate = &ctx.zerocopy_crate;
let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None)
.inner_extras(quote! {
type Tag = ___ZerocopyTag;
type ProjectToTag = #zerocopy_crate::pointer::cast::CastSized;
})
.build();
let has_fields = data.variants().into_iter().flat_map(|(variant, fields)| {
let variant_ident = &variant.unwrap().ident;
let variants_union_field_ident = variants_union_field_ident(variant_ident);
let field: Box<syn::Type> = parse_quote!(());
fields.into_iter().enumerate().map(move |(idx, (vis, ident, ty))| {
// Rust does not presently support explicit visibility modifiers on
// enum fields, but we guard against the possibility to ensure this
// derive remains sound.
assert!(matches!(vis, syn::Visibility::Inherited));
let variant_struct_field_index = Index::from(idx + 1);
let (_, ty_generics, _) = ctx.ast.generics.split_for_impl();
let has_field_trait = Trait::HasField {
variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }),
// Since Rust does not presently support explicit visibility
// modifiers on enum fields, any public type is suitable here;
// we use `()`.
field: field.clone(),
field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }),
};
let has_field_path = has_field_trait.crate_path(ctx);
let has_field = ImplBlockBuilder::new(
ctx,
data,
has_field_trait,
FieldBounds::None,
)
.inner_extras(quote! {
type Type = #ty;
#[inline(always)]
fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut <Self as #has_field_path>::Type {
use #zerocopy_crate::pointer::cast::{CastSized, Projection};
slf.project::<___ZerocopyRawEnum #ty_generics, CastSized>()
.project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(variants) }>>()
.project::<_, Projection<_, { #zerocopy_crate::REPR_C_UNION_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variants_union_field_ident) }>>()
.project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(value) }>>()
.project::<_, Projection<_, { #zerocopy_crate::STRUCT_VARIANT_ID }, { #zerocopy_crate::ident_id!(#variant_struct_field_index) }>>()
.as_ptr()
}
})
.build();
let project = ImplBlockBuilder::new(
ctx,
data,
Trait::ProjectField {
variant_id: parse_quote!({ #zerocopy_crate::ident_id!(#variant_ident) }),
// Since Rust does not presently support explicit visibility
// modifiers on enum fields, any public type is suitable
// here; we use `()`.
field: field.clone(),
field_id: parse_quote!({ #zerocopy_crate::ident_id!(#ident) }),
invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)),
},
FieldBounds::None,
)
.param_extras(vec![
parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing),
parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment),
])
.inner_extras(quote! {
type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible;
type Invariants = (Aliasing, Alignment, #zerocopy_crate::invariant::Initialized);
})
.build();
quote! {
#has_field
#project
}
})
});
let core = ctx.core_path();
let match_arms = data.variants.iter().map(|variant| {
let tag_ident = tag_ident(&variant.ident);
let variant_struct_ident = variant_struct_ident(&variant.ident);
let variants_union_field_ident = variants_union_field_ident(&variant.ident);
if matches!(variant.fields, Fields::Unit) {
// Unit variants don't need any further validation beyond checking
// the tag.
quote! {
#tag_ident => true
}
} else {
quote! {
#tag_ident => {
// SAFETY: Since we know that the tag is `#tag_ident`, we
// know that no other `&`s exist which refer to this enum
// as any other variant.
let variant_md = variants.cast::<
_,
#zerocopy_crate::pointer::cast::Projection<
// #zerocopy_crate::ReadOnly<_>,
_,
{ #zerocopy_crate::REPR_C_UNION_VARIANT_ID },
{ #zerocopy_crate::ident_id!(#variants_union_field_ident) }
>,
_
>();
let variant = variant_md.cast::<
#zerocopy_crate::ReadOnly<#variant_struct_ident #ty_generics>,
#zerocopy_crate::pointer::cast::CastSized,
(#zerocopy_crate::pointer::BecauseRead, _)
>();
<
#variant_struct_ident #ty_generics as #trait_path
>::is_bit_valid(variant)
}
}
}
});
let generics = &ctx.ast.generics;
let raw_enum: DeriveInput = parse_quote! {
#[repr(C)]
struct ___ZerocopyRawEnum #generics {
tag: ___ZerocopyOuterTag,
variants: ___ZerocopyVariants #ty_generics,
}
};
let self_ident = &ctx.ast.ident;
let invariants_eq_impl = quote! {
// SAFETY: `___ZerocopyRawEnum` is designed to have the same layout,
// validity, and invariants as `Self`.
unsafe impl #impl_generics #zerocopy_crate::pointer::InvariantsEq<___ZerocopyRawEnum #ty_generics> for #self_ident #ty_generics #where_clause {}
};
let raw_enum_projections =
derive_has_field_struct_union(&ctx.with_input(&raw_enum), &raw_enum.data);
let raw_enum = quote! {
#raw_enum
#invariants_eq_impl
#raw_enum_projections
};
Ok(quote! {
// SAFETY: We use `is_bit_valid` to validate that the bit pattern of the
// enum's tag corresponds to one of the enum's discriminants. Then, we
// check the bit validity of each field of the corresponding variant.
// Thus, this is a sound implementation of `is_bit_valid`.
#[inline]
fn is_bit_valid<___ZcAlignment>(
mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
) -> #core::primitive::bool
where
___ZcAlignment: #zerocopy_crate::invariant::Alignment,
{
#tag_enum
type ___ZerocopyTagPrimitive = #zerocopy_crate::util::macro_util::SizeToTag<
{ #core::mem::size_of::<___ZerocopyTag>() },
>;
#tag_consts
type ___ZerocopyOuterTag = #outer_tag_type;
type ___ZerocopyInnerTag = #inner_tag_type;
#variant_structs
#variants_union
#raw_enum
#has_tag
#(#has_fields)*
let tag = {
// SAFETY:
// - The provided cast addresses a subset of the bytes addressed
// by `candidate` because it addresses the starting tag of the
// enum.
// - Because the pointer is cast from `candidate`, it has the
// same provenance as it.
// - There are no `UnsafeCell`s in the tag because it is a
// primitive integer.
// - `tag_ptr` is casted from `candidate`, whose referent is
// `Initialized`. Since we have not written uninitialized
// bytes into the referent, `tag_ptr` is also `Initialized`.
//
// FIXME(#2874): Revise this to a `cast` once `candidate`
// references a `ReadOnly<Self>`.
let tag_ptr = unsafe {
candidate.reborrow().project_transmute_unchecked::<
_,
#zerocopy_crate::invariant::Initialized,
#zerocopy_crate::pointer::cast::CastSized
>()
};
tag_ptr.recall_validity::<_, (_, (_, _))>().read::<#zerocopy_crate::BecauseImmutable>()
};
let mut raw_enum = candidate.cast::<
#zerocopy_crate::ReadOnly<___ZerocopyRawEnum #ty_generics>,
#zerocopy_crate::pointer::cast::CastSized,
(#zerocopy_crate::pointer::BecauseRead, _)
>();
let variants = #zerocopy_crate::into_inner!(raw_enum.project::<
_,
{ #zerocopy_crate::STRUCT_VARIANT_ID },
{ #zerocopy_crate::ident_id!(variants) }
>());
match tag {
#(#match_arms,)*
_ => false,
}
}
})
}
pub(crate) fn derive_try_from_bytes(ctx: &Ctx, top_level: Trait) -> Result<TokenStream, Error> {
match &ctx.ast.data {
Data::Struct(strct) => derive_try_from_bytes_struct(ctx, strct, top_level),
Data::Enum(enm) => derive_try_from_bytes_enum(ctx, enm, top_level),
Data::Union(unn) => Ok(derive_try_from_bytes_union(ctx, unn, top_level)),
}
}
fn derive_has_field_struct_union(ctx: &Ctx, data: &dyn DataExt) -> TokenStream {
let fields = ctx.ast.data.fields();
if fields.is_empty() {
return quote! {};
}
let field_tokens = fields.iter().map(|(vis, ident, _)| {
let ident = ident!(("ẕ{}", ident), ident.span());
quote!(
#vis enum #ident {}
)
});
let zerocopy_crate = &ctx.zerocopy_crate;
let variant_id: Box<Expr> = match &ctx.ast.data {
Data::Struct(_) => parse_quote!({ #zerocopy_crate::STRUCT_VARIANT_ID }),
Data::Union(_) => {
let is_repr_c = StructUnionRepr::from_attrs(&ctx.ast.attrs)
.map(|repr| repr.is_c())
.unwrap_or(false);
if is_repr_c {
parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID })
} else {
parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID })
}
}
_ => unreachable!(),
};
let core = ctx.core_path();
let has_tag = ImplBlockBuilder::new(ctx, data, Trait::HasTag, FieldBounds::None)
.inner_extras(quote! {
type Tag = ();
type ProjectToTag = #zerocopy_crate::pointer::cast::CastToUnit;
})
.build();
let has_fields = fields.iter().map(move |(_, ident, ty)| {
let field_token = ident!(("ẕ{}", ident), ident.span());
let field: Box<Type> = parse_quote!(#field_token);
let field_id: Box<Expr> = parse_quote!({ #zerocopy_crate::ident_id!(#ident) });
let has_field_trait = Trait::HasField {
variant_id: variant_id.clone(),
field: field.clone(),
field_id: field_id.clone(),
};
let has_field_path = has_field_trait.crate_path(ctx);
ImplBlockBuilder::new(
ctx,
data,
has_field_trait,
FieldBounds::None,
)
.inner_extras(quote! {
type Type = #ty;
#[inline(always)]
fn project(slf: #zerocopy_crate::pointer::PtrInner<'_, Self>) -> *mut <Self as #has_field_path>::Type {
let slf = slf.as_ptr();
// SAFETY: By invariant on `PtrInner`, `slf` is a non-null
// pointer whose referent is zero-sized or lives in a valid
// allocation. Since `#ident` is a struct or union field of
// `Self`, this projection preserves or shrinks the referent
// size, and so the resulting referent also fits in the same
// allocation.
unsafe { #core::ptr::addr_of_mut!((*slf).#ident) }
}
}).outer_extras(if matches!(&ctx.ast.data, Data::Struct(..)) {
let fields_preserve_alignment = StructUnionRepr::from_attrs(&ctx.ast.attrs)
.map(|repr| repr.get_packed().is_none())
.unwrap();
let alignment = if fields_preserve_alignment {
quote! { Alignment }
} else {
quote! { #zerocopy_crate::invariant::Unaligned }
};
// SAFETY: See comments on items.
ImplBlockBuilder::new(
ctx,
data,
Trait::ProjectField {
variant_id: variant_id.clone(),
field: field.clone(),
field_id: field_id.clone(),
invariants: parse_quote!((Aliasing, Alignment, #zerocopy_crate::invariant::Initialized)),
},
FieldBounds::None,
)
.param_extras(vec![
parse_quote!(Aliasing: #zerocopy_crate::invariant::Aliasing),
parse_quote!(Alignment: #zerocopy_crate::invariant::Alignment),
])
.inner_extras(quote! {
// SAFETY: Projection into structs is always infallible.
type Error = #zerocopy_crate::util::macro_util::core_reexport::convert::Infallible;
// SAFETY: The alignment of the projected `Ptr` is `Unaligned`
// if the structure is packed; otherwise inherited from the
// outer `Ptr`. If the validity of the outer pointer is
// `Initialized`, so too is the validity of its fields.
type Invariants = (Aliasing, #alignment, #zerocopy_crate::invariant::Initialized);
})
.build()
} else {
quote! {}
})
.build()
});
const_block(field_tokens.into_iter().chain(Some(has_tag)).chain(has_fields).map(Some))
}
fn derive_try_from_bytes_struct(
ctx: &Ctx,
strct: &DataStruct,
top_level: Trait,
) -> Result<TokenStream, Error> {
let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| {
let zerocopy_crate = &ctx.zerocopy_crate;
let fields = strct.fields();
let field_names = fields.iter().map(|(_vis, name, _ty)| name);
let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
let core = ctx.core_path();
quote!(
// SAFETY: We use `is_bit_valid` to validate that each field is
// bit-valid, and only return `true` if all of them are. The bit
// validity of a struct is just the composition of the bit
// validities of its fields, so this is a sound implementation
// of `is_bit_valid`.
#[inline]
fn is_bit_valid<___ZcAlignment>(
mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
) -> #core::primitive::bool
where
___ZcAlignment: #zerocopy_crate::invariant::Alignment,
{
true #(&& {
let field_candidate = #zerocopy_crate::into_inner!(candidate.reborrow().project::<
_,
{ #zerocopy_crate::STRUCT_VARIANT_ID },
{ #zerocopy_crate::ident_id!(#field_names) }
>());
<#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
})*
}
)
});
Ok(ImplBlockBuilder::new(ctx, strct, Trait::TryFromBytes, FieldBounds::ALL_SELF)
.inner_extras(extras)
.outer_extras(derive_has_field_struct_union(ctx, strct))
.build())
}
fn derive_try_from_bytes_union(ctx: &Ctx, unn: &DataUnion, top_level: Trait) -> TokenStream {
let field_type_trait_bounds = FieldBounds::All(&[TraitBound::Slf]);
let zerocopy_crate = &ctx.zerocopy_crate;
let variant_id: Box<Expr> = {
let is_repr_c =
StructUnionRepr::from_attrs(&ctx.ast.attrs).map(|repr| repr.is_c()).unwrap_or(false);
if is_repr_c {
parse_quote!({ #zerocopy_crate::REPR_C_UNION_VARIANT_ID })
} else {
parse_quote!({ #zerocopy_crate::UNION_VARIANT_ID })
}
};
let extras = try_gen_trivial_is_bit_valid(ctx, top_level).unwrap_or_else(|| {
let fields = unn.fields();
let field_names = fields.iter().map(|(_vis, name, _ty)| name);
let field_tys = fields.iter().map(|(_vis, _name, ty)| ty);
let core = ctx.core_path();
quote!(
// SAFETY: We use `is_bit_valid` to validate that any field is
// bit-valid; we only return `true` if at least one of them is.
// The bit validity of a union is not yet well defined in Rust,
// but it is guaranteed to be no more strict than this
// definition. See #696 for a more in-depth discussion.
#[inline]
fn is_bit_valid<___ZcAlignment>(
mut candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
) -> #core::primitive::bool
where
___ZcAlignment: #zerocopy_crate::invariant::Alignment,
{
false #(|| {
// SAFETY:
// - Since `ReadOnly<Self>: Immutable` unconditionally,
// neither `*slf` nor the returned pointer's referent
// permit interior mutation.
// - Both source and destination validity are
// `Initialized`, which is always a sound
// transmutation.
let field_candidate = unsafe {
candidate.reborrow().project_transmute_unchecked::<
_,
_,
#zerocopy_crate::pointer::cast::Projection<
_,
#variant_id,
{ #zerocopy_crate::ident_id!(#field_names) }
>
>()
};
<#field_tys as #zerocopy_crate::TryFromBytes>::is_bit_valid(field_candidate)
})*
}
)
});
ImplBlockBuilder::new(ctx, unn, Trait::TryFromBytes, field_type_trait_bounds)
.inner_extras(extras)
.outer_extras(derive_has_field_struct_union(ctx, unn))
.build()
}
fn derive_try_from_bytes_enum(
ctx: &Ctx,
enm: &DataEnum,
top_level: Trait,
) -> Result<TokenStream, Error> {
let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
// If an enum has no fields, it has a well-defined integer representation,
// and every possible bit pattern corresponds to a valid discriminant tag,
// then it *could* be `FromBytes` (even if the user hasn't derived
// `FromBytes`). This holds if, for `repr(uN)` or `repr(iN)`, there are 2^N
// variants.
let could_be_from_bytes = enum_size_from_repr(&repr)
.map(|size| enm.fields().is_empty() && enm.variants.len() == 1usize << size)
.unwrap_or(false);
let trivial_is_bit_valid = try_gen_trivial_is_bit_valid(ctx, top_level);
let extra = match (trivial_is_bit_valid, could_be_from_bytes) {
(Some(is_bit_valid), _) => is_bit_valid,
// SAFETY: It would be sound for the enum to implement `FromBytes`, as
// required by `gen_trivial_is_bit_valid_unchecked`.
(None, true) => unsafe { gen_trivial_is_bit_valid_unchecked(ctx) },
(None, false) => match derive_is_bit_valid(ctx, enm, &repr) {
Ok(extra) => extra,
Err(_) if ctx.skip_on_error => return Ok(TokenStream::new()),
Err(e) => return Err(e),
},
};
Ok(ImplBlockBuilder::new(ctx, enm, Trait::TryFromBytes, FieldBounds::ALL_SELF)
.inner_extras(extra)
.build())
}
fn try_gen_trivial_is_bit_valid(ctx: &Ctx, top_level: Trait) -> Option<proc_macro2::TokenStream> {
// If the top-level trait is `FromBytes` and `Self` has no type parameters,
// then the `FromBytes` derive will fail compilation if `Self` is not
// actually soundly `FromBytes`, and so we can rely on that for our
// `is_bit_valid` impl. It's plausible that we could make changes - or Rust
// could make changes (such as the "trivial bounds" language feature) - that
// make this no longer true. To hedge against these, we include an explicit
// `Self: FromBytes` check in the generated `is_bit_valid`, which is
// bulletproof.
//
// If `ctx.skip_on_error` is true, we can't rely on the `FromBytes` derive
// to fail compilation if `Self` is not actually soundly `FromBytes`.
if matches!(top_level, Trait::FromBytes)
&& ctx.ast.generics.params.is_empty()
&& !ctx.skip_on_error
{
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
Some(quote!(
// SAFETY: See inline.
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
) -> #core::primitive::bool
where
___ZcAlignment: #zerocopy_crate::invariant::Alignment,
{
if false {
fn assert_is_from_bytes<T>()
where
T: #zerocopy_crate::FromBytes,
T: ?#core::marker::Sized,
{
}
assert_is_from_bytes::<Self>();
}
// SAFETY: The preceding code only compiles if `Self:
// FromBytes`. Thus, this code only compiles if all initialized
// byte sequences represent valid instances of `Self`.
true
}
))
} else {
None
}
}
/// # Safety
///
/// All initialized bit patterns must be valid for `Self`.
unsafe fn gen_trivial_is_bit_valid_unchecked(ctx: &Ctx) -> proc_macro2::TokenStream {
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
quote!(
// SAFETY: The caller of `gen_trivial_is_bit_valid_unchecked` has
// promised that all initialized bit patterns are valid for `Self`.
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: #zerocopy_crate::Maybe<'_, Self, ___ZcAlignment>,
) -> #core::primitive::bool
where
___ZcAlignment: #zerocopy_crate::invariant::Alignment,
{
true
}
)
}

View File

@@ -0,0 +1,78 @@
use proc_macro2::{Span, TokenStream};
use syn::{Data, DataEnum, DataStruct, DataUnion, Error};
use crate::{
repr::{EnumRepr, StructUnionRepr},
util::{Ctx, FieldBounds, ImplBlockBuilder, Trait},
};
pub(crate) fn derive_unaligned(ctx: &Ctx, _top_level: Trait) -> Result<TokenStream, Error> {
match &ctx.ast.data {
Data::Struct(strct) => derive_unaligned_struct(ctx, strct),
Data::Enum(enm) => derive_unaligned_enum(ctx, enm),
Data::Union(unn) => derive_unaligned_union(ctx, unn),
}
}
/// 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(ctx: &Ctx, strct: &DataStruct) -> Result<TokenStream, Error> {
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
repr.unaligned_validate_no_align_gt_1()?;
let field_bounds = if repr.is_packed_1() {
FieldBounds::None
} else if repr.is_c() || repr.is_transparent() {
FieldBounds::ALL_SELF
} else {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment",
));
};
Ok(ImplBlockBuilder::new(ctx, strct, Trait::Unaligned, field_bounds).build())
}
/// An enum is `Unaligned` if:
/// - No `repr(align(N > 1))`
/// - `repr(u8)` or `repr(i8)`
fn derive_unaligned_enum(ctx: &Ctx, enm: &DataEnum) -> Result<TokenStream, Error> {
let repr = EnumRepr::from_attrs(&ctx.ast.attrs)?;
repr.unaligned_validate_no_align_gt_1()?;
if !repr.is_u8() && !repr.is_i8() {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment",
));
}
Ok(ImplBlockBuilder::new(ctx, enm, Trait::Unaligned, FieldBounds::ALL_SELF).build())
}
/// 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(ctx: &Ctx, unn: &DataUnion) -> Result<TokenStream, Error> {
let repr = StructUnionRepr::from_attrs(&ctx.ast.attrs)?;
repr.unaligned_validate_no_align_gt_1()?;
let field_type_trait_bounds = if repr.is_packed_1() {
FieldBounds::None
} else if repr.is_c() || repr.is_transparent() {
FieldBounds::ALL_SELF
} else {
return ctx.error_or_skip(Error::new(
Span::call_site(),
"must have #[repr(C)], #[repr(transparent)], or #[repr(packed)] attribute in order to guarantee this type's alignment",
));
};
Ok(ImplBlockBuilder::new(ctx, unn, Trait::Unaligned, field_type_trait_bounds).build())
}

144
vendor/zerocopy-derive/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,144 @@
// 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::multiple_unsafe_ops_per_block,
clippy::undocumented_unsafe_blocks
)]
// We defer to own discretion on type complexity.
#![allow(clippy::type_complexity)]
// Inlining format args isn't supported on our MSRV.
#![allow(clippy::uninlined_format_args)]
#![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"]
macro_rules! ident {
(($fmt:literal $(, $arg:expr)*), $span:expr) => {
syn::Ident::new(&format!($fmt $(, crate::util::to_ident_str($arg))*), $span)
};
}
mod derive;
#[cfg(test)]
mod output_tests;
mod repr;
mod util;
use syn::{DeriveInput, Error};
use crate::util::*;
// FIXME(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 FromZeros, FromBytes, IntoBytes, 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.
/// Defines a derive function named `$outer` which parses its input
/// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function.
///
/// Note that the separate `$outer` parameter is required - proc macro functions
/// are currently required to live at the crate root, and so the caller must
/// specify the name in order to avoid name collisions.
macro_rules! derive {
($trait:ident => $outer:ident => $inner:path) => {
#[proc_macro_derive($trait, attributes(zerocopy))]
pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(ts as DeriveInput);
let ctx = match Ctx::try_from_derive_input(ast) {
Ok(ctx) => ctx,
Err(e) => return e.into_compile_error().into(),
};
let ts = $inner(&ctx, Trait::$trait).into_ts();
// We wrap in `const_block` as a backstop in case any derive fails
// to wrap its output in `const_block` (and thus fails to annotate)
// with the full set of `#[allow(...)]` attributes).
let ts = const_block([Some(ts)]);
#[cfg(test)]
crate::util::testutil::check_hygiene(ts.clone());
ts.into()
}
};
}
trait IntoTokenStream {
fn into_ts(self) -> proc_macro2::TokenStream;
}
impl IntoTokenStream for proc_macro2::TokenStream {
fn into_ts(self) -> proc_macro2::TokenStream {
self
}
}
impl IntoTokenStream for Result<proc_macro2::TokenStream, Error> {
fn into_ts(self) -> proc_macro2::TokenStream {
match self {
Ok(ts) => ts,
Err(err) => err.to_compile_error(),
}
}
}
derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive);
derive!(Immutable => derive_immutable => crate::derive::derive_immutable);
derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes);
derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros);
derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes);
derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes);
derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned);
derive!(ByteHash => derive_hash => crate::derive::derive_hash);
derive!(ByteEq => derive_eq => crate::derive::derive_eq);
derive!(SplitAt => derive_split_at => crate::derive::derive_split_at);
/// Deprecated: prefer [`FromZeros`] instead.
#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
#[doc(hidden)]
#[proc_macro_derive(FromZeroes)]
pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_from_zeros(ts)
}
/// Deprecated: prefer [`IntoBytes`] instead.
#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")]
#[doc(hidden)]
#[proc_macro_derive(AsBytes)]
pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_into_bytes(ts)
}

View File

@@ -0,0 +1,17 @@
impl<T: Clone> ::zerocopy::util::macro_util::core_reexport::cmp::PartialEq for Foo<T>
where
Self: ::zerocopy::IntoBytes + ::zerocopy::Immutable,
Self: Sized,
{
fn eq(&self, other: &Self) -> bool {
::zerocopy::util::macro_util::core_reexport::cmp::PartialEq::eq(
::zerocopy::IntoBytes::as_bytes(self),
::zerocopy::IntoBytes::as_bytes(other),
)
}
}
impl<T: Clone> ::zerocopy::util::macro_util::core_reexport::cmp::Eq for Foo<T>
where
Self: ::zerocopy::IntoBytes + ::zerocopy::Immutable,
Self: Sized,
{}

View File

@@ -0,0 +1,68 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
if false {
fn assert_is_from_bytes<T>()
where
T: ::zerocopy::FromBytes,
T: ?::zerocopy::util::macro_util::core_reexport::marker::Sized,
{}
assert_is_from_bytes::<Self>();
}
true
}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromZeros for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,68 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
if false {
fn assert_is_from_bytes<T>()
where
T: ::zerocopy::FromBytes,
T: ?::zerocopy::util::macro_util::core_reexport::marker::Sized,
{}
assert_is_from_bytes::<Self>();
}
true
}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromZeros for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,148 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo
where
u8: ::zerocopy::TryFromBytes,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
if false {
fn assert_is_from_bytes<T>()
where
T: ::zerocopy::FromBytes,
T: ?::zerocopy::util::macro_util::core_reexport::marker::Sized,
{}
assert_is_from_bytes::<Self>();
}
true
}
}
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
enum a {}
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::HasTag for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
type Tag = ();
type ProjectToTag = ::zerocopy::pointer::cast::CastToUnit;
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::HasField<
a,
{ ::zerocopy::UNION_VARIANT_ID },
{ ::zerocopy::ident_id!(a) },
> for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
type Type = u8;
#[inline(always)]
fn project(
slf: ::zerocopy::pointer::PtrInner<'_, Self>,
) -> *mut <Self as ::zerocopy::HasField<
a,
{ ::zerocopy::UNION_VARIANT_ID },
{ ::zerocopy::ident_id!(a) },
>>::Type {
let slf = slf.as_ptr();
unsafe {
::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!(
(* slf).a
)
}
}
}
};
};
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromZeros for Foo
where
u8: ::zerocopy::FromZeros,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromBytes for Foo
where
u8: ::zerocopy::FromBytes,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,43 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline]
fn is_bit_valid<___ZcAlignment>(
mut candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
true
}
}
};
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::FromZeros for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,24 @@
impl<T: Clone> ::zerocopy::util::macro_util::core_reexport::hash::Hash for Foo<T>
where
Self: ::zerocopy::IntoBytes + ::zerocopy::Immutable,
Self: Sized,
{
fn hash<H: ::zerocopy::util::macro_util::core_reexport::hash::Hasher>(
&self,
state: &mut H,
) {
::zerocopy::util::macro_util::core_reexport::hash::Hasher::write(
state,
::zerocopy::IntoBytes::as_bytes(self),
)
}
fn hash_slice<H: ::zerocopy::util::macro_util::core_reexport::hash::Hasher>(
data: &[Self],
state: &mut H,
) {
::zerocopy::util::macro_util::core_reexport::hash::Hasher::write(
state,
::zerocopy::IntoBytes::as_bytes(data),
)
}
}

View File

@@ -0,0 +1,17 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::Immutable for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(C)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(i128)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(i16)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(i32)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(i64)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(i8)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(isize)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(u128)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(u16)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(u32)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(u64)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(u8)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,40 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
#[repr(usize)]
#[allow(dead_code)]
pub enum ___ZerocopyTag {
Bar,
}
unsafe impl ::zerocopy::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
::zerocopy::enum_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
___ZerocopyTag, []
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,34 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
u8: ::zerocopy::IntoBytes,
u8: ::zerocopy::IntoBytes,
(): ::zerocopy::util::macro_util::PaddingFree<
Self,
{
::zerocopy::struct_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
[(u8), (u8)]
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,17 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,34 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::IntoBytes for Foo
where
u8: ::zerocopy::IntoBytes,
[Trailing]: ::zerocopy::IntoBytes,
(): ::zerocopy::util::macro_util::DynamicPaddingFree<
Self,
{
::zerocopy::repr_c_struct_has_padding!(
Self,
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
(::zerocopy::util::macro_util::core_reexport::option::Option::None::
< ::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize >),
[(u8), ([Trailing])]
)
},
>,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,21 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl<Trailing> ::zerocopy::IntoBytes for Foo<Trailing>
where
u8: ::zerocopy::IntoBytes + ::zerocopy::Unaligned,
[Trailing]: ::zerocopy::IntoBytes + ::zerocopy::Unaligned,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,135 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl<T, U> ::zerocopy::KnownLayout for Foo<T, U>
where
U: ::zerocopy::KnownLayout,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = <U as ::zerocopy::KnownLayout>::PointerMetadata;
type MaybeUninit = __ZerocopyKnownLayoutMaybeUninit<T, U>;
const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_repr_c_struct(
::zerocopy::util::macro_util::core_reexport::num::NonZeroUsize::new(
2u32 as usize,
),
::zerocopy::util::macro_util::core_reexport::option::Option::None,
&[
::zerocopy::DstLayout::for_type::<T>(),
<U as ::zerocopy::KnownLayout>::LAYOUT,
],
);
#[inline(always)]
fn raw_from_ptr_len(
bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<u8>,
meta: <Self as ::zerocopy::KnownLayout>::PointerMetadata,
) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<Self> {
let trailing = <U as ::zerocopy::KnownLayout>::raw_from_ptr_len(bytes, meta);
let slf = trailing.as_ptr() as *mut Self;
unsafe {
::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(
slf,
)
}
}
#[inline(always)]
fn pointer_to_metadata(
ptr: *mut Self,
) -> <Self as ::zerocopy::KnownLayout>::PointerMetadata {
<U>::pointer_to_metadata(ptr as *mut _)
}
}
struct __Zerocopy_Field_0;
struct __Zerocopy_Field_1;
unsafe impl<T, U> ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0>
for Foo<T, U> {
type Type = T;
}
unsafe impl<T, U> ::zerocopy::util::macro_util::Field<__Zerocopy_Field_1>
for Foo<T, U> {
type Type = U;
}
#[repr(C)]
#[repr(align(2))]
#[doc(hidden)]
struct __ZerocopyKnownLayoutMaybeUninit<T, U>(
::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit<
<Foo<T, U> as ::zerocopy::util::macro_util::Field<__Zerocopy_Field_0>>::Type,
>,
::zerocopy::util::macro_util::core_reexport::mem::ManuallyDrop<
<<Foo<
T,
U,
> as ::zerocopy::util::macro_util::Field<
__Zerocopy_Field_1,
>>::Type as ::zerocopy::KnownLayout>::MaybeUninit,
>,
)
where
<Foo<
T,
U,
> as ::zerocopy::util::macro_util::Field<
__Zerocopy_Field_1,
>>::Type: ::zerocopy::KnownLayout;
unsafe impl<T, U> ::zerocopy::KnownLayout for __ZerocopyKnownLayoutMaybeUninit<T, U>
where
<Foo<
T,
U,
> as ::zerocopy::util::macro_util::Field<
__Zerocopy_Field_1,
>>::Type: ::zerocopy::KnownLayout,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = <Foo<T, U> as ::zerocopy::KnownLayout>::PointerMetadata;
type MaybeUninit = Self;
const LAYOUT: ::zerocopy::DstLayout = <Foo<
T,
U,
> as ::zerocopy::KnownLayout>::LAYOUT;
#[inline(always)]
fn raw_from_ptr_len(
bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<u8>,
meta: <Self as ::zerocopy::KnownLayout>::PointerMetadata,
) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<Self> {
let trailing = <<<Foo<
T,
U,
> as ::zerocopy::util::macro_util::Field<
__Zerocopy_Field_1,
>>::Type as ::zerocopy::KnownLayout>::MaybeUninit as ::zerocopy::KnownLayout>::raw_from_ptr_len(
bytes,
meta,
);
let slf = trailing.as_ptr() as *mut Self;
unsafe {
::zerocopy::util::macro_util::core_reexport::ptr::NonNull::new_unchecked(
slf,
)
}
}
#[inline(always)]
fn pointer_to_metadata(
ptr: *mut Self,
) -> <Self as ::zerocopy::KnownLayout>::PointerMetadata {
<<<Foo<
T,
U,
> as ::zerocopy::util::macro_util::Field<
__Zerocopy_Field_1,
>>::Type as ::zerocopy::KnownLayout>::MaybeUninit>::pointer_to_metadata(
ptr as *mut _,
)
}
}
};

View File

@@ -0,0 +1,34 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::KnownLayout for Foo
where
Self: ::zerocopy::util::macro_util::core_reexport::marker::Sized,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type PointerMetadata = ();
type MaybeUninit = ::zerocopy::util::macro_util::core_reexport::mem::MaybeUninit<
Self,
>;
const LAYOUT: ::zerocopy::DstLayout = ::zerocopy::DstLayout::for_type::<Self>();
#[inline(always)]
fn raw_from_ptr_len(
bytes: ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<u8>,
_meta: (),
) -> ::zerocopy::util::macro_util::core_reexport::ptr::NonNull<Self> {
bytes.cast::<Self>()
}
#[inline(always)]
fn pointer_to_metadata(_ptr: *mut Self) -> () {}
}
};

View File

@@ -0,0 +1,22 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl<T: ?Sized + Copy> ::zerocopy::SplitAt for Foo<T>
where
Self: Copy,
T: ::zerocopy::SplitAt,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type Elem = <T as ::zerocopy::SplitAt>::Elem;
}
};

View File

@@ -0,0 +1,22 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl<T: ?Sized + Copy> ::zerocopy::SplitAt for Foo<T>
where
Self: Copy,
T: ::zerocopy::SplitAt,
{
fn only_derive_is_allowed_to_implement_this_trait() {}
type Elem = <T as ::zerocopy::SplitAt>::Elem;
}
};

View File

@@ -0,0 +1,26 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline]
fn is_bit_valid<___ZcAlignment>(
mut candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
true
}
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::TryFromBytes for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
#[inline(always)]
fn is_bit_valid<___ZcAlignment>(
_candidate: ::zerocopy::Maybe<'_, Self, ___ZcAlignment>,
) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool
where
___ZcAlignment: ::zerocopy::invariant::Alignment,
{
true
}
}
};

View File

@@ -0,0 +1,17 @@
#[allow(
deprecated,
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
#[automatically_derived]
const _: () = {
unsafe impl ::zerocopy::Unaligned for Foo {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
};

View File

@@ -0,0 +1,960 @@
// Copyright 2024 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 std::path::Path;
use dissimilar::Chunk;
use proc_macro2::TokenStream;
use crate::IntoTokenStream;
macro_rules! use_as_trait_name {
($($alias:ident => $derive:path),* $(,)?) => {
$(use $derive as $alias;)*
};
}
// This permits invocations of `test!` to be more ergonomic, passing the name of
// the trait under test rather than the name of the inner derive function.
use_as_trait_name!(
KnownLayout => super::derive::known_layout::derive,
Immutable => super::derive::derive_immutable,
TryFromBytes => super::derive::try_from_bytes::derive_try_from_bytes,
FromZeros => super::derive::from_bytes::derive_from_zeros,
FromBytes => super::derive::from_bytes::derive_from_bytes,
IntoBytes => super::derive::into_bytes::derive_into_bytes,
Unaligned => super::derive::unaligned::derive_unaligned,
ByteHash => super::derive::derive_hash,
ByteEq => super::derive::derive_eq,
SplitAt => super::derive::derive_split_at,
);
/// Test that the given derive input expands to the expected output.
///
/// Equality is tested by formatting both token streams using `prettyplease` and
/// performing string equality on the results. This has the effect of making the
/// tests less brittle and robust against meaningless formatting changes.
// Adapted from https://github.com/joshlf/synstructure/blob/400499aaf54840056ff56718beb7810540e6be59/src/macros.rs#L212-L317
macro_rules! test {
($name:ident { $($i:tt)* } expands to { $($o:tt)* }) => {
{
#[allow(dead_code)]
fn ensure_compiles() {
$($i)*
$($o)*
}
test!($name { $($i)* } expands to { $($o)* } no_build);
}
};
($name:ident { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
{
let ts: proc_macro2::TokenStream = quote::quote!( $($i)* );
let ast = syn::parse2::<syn::DeriveInput>(ts).unwrap();
let ctx = crate::Ctx::try_from_derive_input(ast).unwrap();
let res = $name(&ctx, crate::util::Trait::$name);
let expected_toks = quote::quote!( $($o)* );
let expected = pretty_print(expected_toks);
let actual = pretty_print(res.into_ts().into());
assert_eq_or_diff(&expected, &actual);
}
};
($name:ident { $($i:tt)* } expands to $path:expr) => {
test!($name { $($i)* } expands to $path; no_build);
};
($name:ident { $($i:tt)* } expands to $path:expr; no_build) => {
{
let ts: proc_macro2::TokenStream = quote::quote!( $($i)* );
let ast = syn::parse2::<syn::DeriveInput>(ts).unwrap();
let ctx = crate::Ctx::try_from_derive_input(ast).unwrap();
let res = $name(&ctx, crate::util::Trait::$name);
let actual = pretty_print(res.into_ts().into());
if std::env::var("ZEROCOPY_BLESS").is_ok() {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("src/output_tests")
.join($path);
std::fs::write(&path, &actual).expect("failed to bless output");
} else {
let expected_str = include_str!($path);
let expected_ts: proc_macro2::TokenStream = expected_str.parse().expect("failed to parse expected output");
let expected = pretty_print(expected_ts);
assert_eq_or_diff(&expected, &actual);
}
}
};
}
fn pretty_print(ts: TokenStream) -> String {
prettyplease::unparse(&syn::parse_file(&ts.to_string()).unwrap())
}
#[track_caller]
fn assert_eq_or_diff(expected: &str, actual: &str) {
if expected != actual {
let diff = dissimilar::diff(expected, actual)
.into_iter()
.flat_map(|chunk| {
let (prefix, chunk) = match chunk {
Chunk::Equal(chunk) => (" ", chunk),
Chunk::Delete(chunk) => ("-", chunk),
Chunk::Insert(chunk) => ("+", chunk),
};
[prefix, chunk, "\n"]
})
.collect::<String>();
panic!(
"\
test failed:
got:
```
{}
```
diff (expected vs got):
```
{}
```\n",
actual, diff
);
}
}
#[test]
fn test_known_layout_struct() {
test! {
KnownLayout {
struct Foo;
} expands to "expected/known_layout_struct.expected.rs"
}
}
#[test]
fn test_known_layout_repr_c_struct() {
test! {
KnownLayout {
#[repr(C, align(2))]
struct Foo<T, U>(T, U);
}
expands to "expected/known_layout_repr_c_struct.expected.rs"
}
}
#[test]
fn test_immutable() {
test! {
Immutable {
struct Foo;
} expands to "expected/immutable.expected.rs"
}
}
#[test]
fn test_try_from_bytes() {
test! {
TryFromBytes {
struct Foo;
} expands to "expected/try_from_bytes.expected.rs"
}
}
#[test]
fn test_from_zeros() {
test! {
FromZeros {
struct Foo;
} expands to "expected/from_zeros.expected.rs"
}
}
#[test]
fn test_from_bytes_struct() {
test! {
FromBytes {
struct Foo;
} expands to "expected/from_bytes_struct.expected.rs"
}
}
#[test]
fn test_from_bytes_union() {
test! {
FromBytes {
union Foo {
a: u8,
}
} expands to "expected/from_bytes_union.expected.rs"
}
}
#[test]
fn test_into_bytes_struct_empty() {
test! {
IntoBytes {
#[repr(C)]
struct Foo;
} expands to "expected/into_bytes_struct_empty.expected.rs"
}
}
#[test]
fn test_into_bytes_struct_basic() {
test! {
IntoBytes {
#[repr(C)]
struct Foo {
a: u8,
b: u8,
}
} expands to "expected/into_bytes_struct_basic.expected.rs"
}
}
#[test]
fn test_into_bytes_struct_trailing() {
test! {
IntoBytes {
#[repr(C)]
struct Foo {
a: u8,
b: [Trailing],
}
} expands to "expected/into_bytes_struct_trailing.expected.rs"
}
}
#[test]
fn test_into_bytes_struct_trailing_generic() {
test! {
IntoBytes {
#[repr(C)]
struct Foo<Trailing> {
a: u8,
b: [Trailing],
}
} expands to "expected/into_bytes_struct_trailing_generic.expected.rs"
}
}
#[test]
fn test_into_bytes_enum() {
macro_rules! test_repr {
($(#[$attr:meta])*) => {
$(test! {
IntoBytes {
#[$attr]
enum Foo {
Bar,
}
} expands to concat!("expected/into_bytes_enum.", stringify!($attr), ".expected.rs")
})*
};
}
test_repr! {
#[repr(C)]
#[repr(u8)]
#[repr(u16)]
#[repr(u32)]
#[repr(u64)]
#[repr(u128)]
#[repr(usize)]
#[repr(i8)]
#[repr(i16)]
#[repr(i32)]
#[repr(i64)]
#[repr(i128)]
#[repr(isize)]
}
}
#[test]
fn test_unaligned() {
test! {
Unaligned {
#[repr(C)]
struct Foo;
} expands to "expected/unaligned.expected.rs"
}
}
#[test]
fn test_try_from_bytes_enum() {
test! {
TryFromBytes {
#[repr(u8)]
enum ComplexWithGenerics<'a: 'static, const N: usize, X, Y: Deref>
where
X: Deref<Target = &'a [(X, Y); N]>,
{
UnitLike,
StructLike { a: u8, b: X, c: X::Target, d: Y::Target, e: [(X, Y); N] },
TupleLike(bool, Y, PhantomData<&'a [(X, Y); N]>),
}
} expands to "expected/try_from_bytes_enum_1.expected.rs"
}
test! {
TryFromBytes {
#[repr(u32)]
enum ComplexWithGenerics<'a: 'static, const N: usize, X, Y: Deref>
where
X: Deref<Target = &'a [(X, Y); N]>,
{
UnitLike,
StructLike { a: u8, b: X, c: X::Target, d: Y::Target, e: [(X, Y); N] },
TupleLike(bool, Y, PhantomData<&'a [(X, Y); N]>),
}
} expands to "expected/try_from_bytes_enum_2.expected.rs"
}
test! {
TryFromBytes {
#[repr(C)]
enum ComplexWithGenerics<'a: 'static, const N: usize, X, Y: Deref>
where
X: Deref<Target = &'a [(X, Y); N]>,
{
UnitLike,
StructLike { a: u8, b: X, c: X::Target, d: Y::Target, e: [(X, Y); N] },
TupleLike(bool, Y, PhantomData<&'a [(X, Y); N]>),
}
} expands to "expected/try_from_bytes_enum_3.expected.rs"
}
}
// This goes at the bottom because it's so verbose and it makes scrolling past
// other code a pain.
#[test]
fn test_from_bytes_enum() {
test! {
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,
Variant255,
}
} expands to "expected/from_bytes_enum.expected.rs"
}
}
#[test]
fn test_try_from_bytes_trivial_is_bit_valid_enum() {
// Even when we aren't deriving `FromBytes` as the top-level trait,
// `TryFromBytes` on enums still detects whether we *could* derive
// `FromBytes`, and if so, performs the same "trivial `is_bit_valid`"
// optimization.
test! {
TryFromBytes {
#[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,
Variant255,
}
} expands to "expected/try_from_bytes_trivial_is_bit_valid_enum.expected.rs"
}
}
#[test]
fn test_hash() {
test! {
ByteHash {
struct Foo<T: Clone>(T) where Self: Sized;
} expands to "expected/hash.expected.rs"
}
}
#[test]
fn test_eq() {
test! {
ByteEq {
struct Foo<T: Clone>(T) where Self: Sized;
} expands to "expected/eq.expected.rs"
}
}
#[test]
fn test_split_at() {
test! {
SplitAt {
#[repr(C)]
struct Foo<T: ?Sized + Copy>(T) where Self: Copy;
} expands to "expected/split_at_repr_c.expected.rs"
}
test! {
SplitAt {
#[repr(transparent)]
struct Foo<T: ?Sized + Copy>(T) where Self: Copy;
} expands to "expected/split_at_repr_transparent.expected.rs"
}
test! {
SplitAt {
#[repr(packed)]
struct Foo<T: ?Sized + Copy>(T) where Self: Copy;
} expands to {
::core::compile_error! {
"must not have #[repr(packed)] attribute"
}
} no_build
}
test! {
SplitAt {
#[repr(packed(2))]
struct Foo<T: ?Sized + Copy>(T) where Self: Copy;
} expands to {
::core::compile_error! {
"must not have #[repr(packed)] attribute"
}
} no_build
}
test! {
SplitAt {
enum Foo {}
} expands to {
::core::compile_error! {
"can only be applied to structs"
}
} no_build
}
test! {
SplitAt {
union Foo { a: () }
} expands to {
::core::compile_error! {
"can only be applied to structs"
}
} no_build
}
test! {
SplitAt {
struct Foo<T: ?Sized + Copy>(T) where Self: Copy;
} expands to {
::core::compile_error! {
"must have #[repr(C)] or #[repr(transparent)] in order to guarantee this type's layout is splitable"
}
} no_build
}
}

849
vendor/zerocopy-derive/src/repr.rs vendored Normal file
View File

@@ -0,0 +1,849 @@
// 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::{
convert::{Infallible, TryFrom},
num::NonZeroU32,
};
use proc_macro2::{Span, TokenStream};
use quote::{quote_spanned, ToTokens, TokenStreamExt as _};
use syn::{
punctuated::Punctuated, spanned::Spanned as _, token::Comma, Attribute, Error, LitInt, Meta,
MetaList,
};
/// The computed representation of a type.
///
/// This is the result of processing all `#[repr(...)]` attributes on a type, if
/// any. A `Repr` is only capable of representing legal combinations of
/// `#[repr(...)]` attributes.
#[cfg_attr(test, derive(Copy, Clone, Debug))]
pub(crate) enum Repr<Prim, Packed> {
/// `#[repr(transparent)]`
Transparent(Span),
/// A compound representation: `repr(C)`, `repr(Rust)`, or `repr(Int)`
/// optionally combined with `repr(packed(...))` or `repr(align(...))`
Compound(Spanned<CompoundRepr<Prim>>, Option<Spanned<AlignRepr<Packed>>>),
}
/// A compound representation: `repr(C)`, `repr(Rust)`, or `repr(Int)`.
#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
pub(crate) enum CompoundRepr<Prim> {
C,
Rust,
Primitive(Prim),
}
/// `repr(Int)`
#[derive(Copy, Clone)]
#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
pub(crate) enum PrimitiveRepr {
U8,
U16,
U32,
U64,
U128,
Usize,
I8,
I16,
I32,
I64,
I128,
Isize,
}
/// `repr(packed(...))` or `repr(align(...))`
#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
pub(crate) enum AlignRepr<Packed> {
Packed(Packed),
Align(NonZeroU32),
}
/// The representations which can legally appear on a struct or union type.
pub(crate) type StructUnionRepr = Repr<Infallible, NonZeroU32>;
/// The representations which can legally appear on an enum type.
pub(crate) type EnumRepr = Repr<PrimitiveRepr, Infallible>;
impl<Prim, Packed> Repr<Prim, Packed> {
/// Gets the name of this "repr type" - the non-align `repr(X)` that is used
/// in prose to refer to this type.
///
/// For example, we would refer to `#[repr(C, align(4))] struct Foo { ... }`
/// as a "`repr(C)` struct".
pub(crate) fn repr_type_name(&self) -> &str
where
Prim: Copy + With<PrimitiveRepr>,
{
use CompoundRepr::*;
use PrimitiveRepr::*;
use Repr::*;
match self {
Transparent(_span) => "repr(transparent)",
Compound(Spanned { t: repr, span: _ }, _align) => match repr {
C => "repr(C)",
Rust => "repr(Rust)",
Primitive(prim) => prim.with(|prim| match prim {
U8 => "repr(u8)",
U16 => "repr(u16)",
U32 => "repr(u32)",
U64 => "repr(u64)",
U128 => "repr(u128)",
Usize => "repr(usize)",
I8 => "repr(i8)",
I16 => "repr(i16)",
I32 => "repr(i32)",
I64 => "repr(i64)",
I128 => "repr(i128)",
Isize => "repr(isize)",
}),
},
}
}
pub(crate) fn is_transparent(&self) -> bool {
matches!(self, Repr::Transparent(_))
}
pub(crate) fn is_c(&self) -> bool {
use CompoundRepr::*;
matches!(self, Repr::Compound(Spanned { t: C, span: _ }, _align))
}
pub(crate) fn is_primitive(&self) -> bool {
use CompoundRepr::*;
matches!(self, Repr::Compound(Spanned { t: Primitive(_), span: _ }, _align))
}
pub(crate) fn get_packed(&self) -> Option<&Packed> {
use AlignRepr::*;
use Repr::*;
if let Compound(_, Some(Spanned { t: Packed(p), span: _ })) = self {
Some(p)
} else {
None
}
}
pub(crate) fn get_align(&self) -> Option<Spanned<NonZeroU32>> {
use AlignRepr::*;
use Repr::*;
if let Compound(_, Some(Spanned { t: Align(n), span })) = self {
Some(Spanned::new(*n, *span))
} else {
None
}
}
pub(crate) fn is_align_gt_1(&self) -> bool {
self.get_align().map(|n| n.t.get() > 1).unwrap_or(false)
}
/// When deriving `Unaligned`, validate that the decorated type has no
/// `#[repr(align(N))]` attribute where `N > 1`. If no such attribute exists
/// (including if `N == 1`), this returns `Ok(())`, and otherwise it returns
/// a descriptive error.
pub(crate) fn unaligned_validate_no_align_gt_1(&self) -> Result<(), Error> {
if let Some(n) = self.get_align().filter(|n| n.t.get() > 1) {
Err(Error::new(
n.span,
"cannot derive `Unaligned` on type with alignment greater than 1",
))
} else {
Ok(())
}
}
}
impl<Prim> Repr<Prim, NonZeroU32> {
/// Does `self` describe a `#[repr(packed)]` or `#[repr(packed(1))]` type?
pub(crate) fn is_packed_1(&self) -> bool {
self.get_packed().map(|n| n.get() == 1).unwrap_or(false)
}
}
impl<Packed> Repr<PrimitiveRepr, Packed> {
fn get_primitive(&self) -> Option<&PrimitiveRepr> {
use CompoundRepr::*;
use Repr::*;
if let Compound(Spanned { t: Primitive(p), span: _ }, _align) = self {
Some(p)
} else {
None
}
}
/// Does `self` describe a `#[repr(u8)]` type?
pub(crate) fn is_u8(&self) -> bool {
matches!(self.get_primitive(), Some(PrimitiveRepr::U8))
}
/// Does `self` describe a `#[repr(i8)]` type?
pub(crate) fn is_i8(&self) -> bool {
matches!(self.get_primitive(), Some(PrimitiveRepr::I8))
}
}
impl<Prim, Packed> ToTokens for Repr<Prim, Packed>
where
Prim: With<PrimitiveRepr> + Copy,
Packed: With<NonZeroU32> + Copy,
{
fn to_tokens(&self, ts: &mut TokenStream) {
use Repr::*;
match self {
Transparent(span) => ts.append_all(quote_spanned! { *span=> #[repr(transparent)] }),
Compound(repr, align) => {
repr.to_tokens(ts);
if let Some(align) = align {
align.to_tokens(ts);
}
}
}
}
}
impl<Prim: With<PrimitiveRepr> + Copy> ToTokens for Spanned<CompoundRepr<Prim>> {
fn to_tokens(&self, ts: &mut TokenStream) {
use CompoundRepr::*;
match &self.t {
C => ts.append_all(quote_spanned! { self.span=> #[repr(C)] }),
Rust => ts.append_all(quote_spanned! { self.span=> #[repr(Rust)] }),
Primitive(prim) => prim.with(|prim| Spanned::new(prim, self.span).to_tokens(ts)),
}
}
}
impl ToTokens for Spanned<PrimitiveRepr> {
fn to_tokens(&self, ts: &mut TokenStream) {
use PrimitiveRepr::*;
match self.t {
U8 => ts.append_all(quote_spanned! { self.span => #[repr(u8)] }),
U16 => ts.append_all(quote_spanned! { self.span => #[repr(u16)] }),
U32 => ts.append_all(quote_spanned! { self.span => #[repr(u32)] }),
U64 => ts.append_all(quote_spanned! { self.span => #[repr(u64)] }),
U128 => ts.append_all(quote_spanned! { self.span => #[repr(u128)] }),
Usize => ts.append_all(quote_spanned! { self.span => #[repr(usize)] }),
I8 => ts.append_all(quote_spanned! { self.span => #[repr(i8)] }),
I16 => ts.append_all(quote_spanned! { self.span => #[repr(i16)] }),
I32 => ts.append_all(quote_spanned! { self.span => #[repr(i32)] }),
I64 => ts.append_all(quote_spanned! { self.span => #[repr(i64)] }),
I128 => ts.append_all(quote_spanned! { self.span => #[repr(i128)] }),
Isize => ts.append_all(quote_spanned! { self.span => #[repr(isize)] }),
}
}
}
impl<Packed: With<NonZeroU32> + Copy> ToTokens for Spanned<AlignRepr<Packed>> {
fn to_tokens(&self, ts: &mut TokenStream) {
use AlignRepr::*;
// We use `syn::Index` instead of `u32` because `quote_spanned!`
// serializes `u32` literals as `123u32`, not just `123`. Rust doesn't
// recognize that as a valid argument to `#[repr(align(...))]` or
// `#[repr(packed(...))]`.
let to_index = |n: NonZeroU32| syn::Index { index: n.get(), span: self.span };
match self.t {
Packed(n) => n.with(|n| {
let n = to_index(n);
ts.append_all(quote_spanned! { self.span => #[repr(packed(#n))] })
}),
Align(n) => {
let n = to_index(n);
ts.append_all(quote_spanned! { self.span => #[repr(align(#n))] })
}
}
}
}
/// The result of parsing a single `#[repr(...)]` attribute or a single
/// directive inside a compound `#[repr(..., ...)]` attribute.
#[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(test, derive(Debug))]
pub(crate) enum RawRepr {
Transparent,
C,
Rust,
U8,
U16,
U32,
U64,
U128,
Usize,
I8,
I16,
I32,
I64,
I128,
Isize,
Align(NonZeroU32),
PackedN(NonZeroU32),
Packed,
}
/// The error from converting from a `RawRepr`.
#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
pub(crate) enum FromRawReprError<E> {
/// The `RawRepr` doesn't affect the high-level repr we're parsing (e.g.
/// it's `align(...)` and we're parsing a `CompoundRepr`).
None,
/// The `RawRepr` is invalid for the high-level repr we're parsing (e.g.
/// it's `packed` repr and we're parsing an `AlignRepr` for an enum type).
Err(E),
}
/// The representation hint is not supported for the decorated type.
#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
pub(crate) struct UnsupportedReprError;
impl<Prim: With<PrimitiveRepr>> TryFrom<RawRepr> for CompoundRepr<Prim> {
type Error = FromRawReprError<UnsupportedReprError>;
fn try_from(
raw: RawRepr,
) -> Result<CompoundRepr<Prim>, FromRawReprError<UnsupportedReprError>> {
use RawRepr::*;
match raw {
C => Ok(CompoundRepr::C),
Rust => Ok(CompoundRepr::Rust),
raw @ (U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize) => {
Prim::try_with_or(
|| match raw {
U8 => Ok(PrimitiveRepr::U8),
U16 => Ok(PrimitiveRepr::U16),
U32 => Ok(PrimitiveRepr::U32),
U64 => Ok(PrimitiveRepr::U64),
U128 => Ok(PrimitiveRepr::U128),
Usize => Ok(PrimitiveRepr::Usize),
I8 => Ok(PrimitiveRepr::I8),
I16 => Ok(PrimitiveRepr::I16),
I32 => Ok(PrimitiveRepr::I32),
I64 => Ok(PrimitiveRepr::I64),
I128 => Ok(PrimitiveRepr::I128),
Isize => Ok(PrimitiveRepr::Isize),
Transparent | C | Rust | Align(_) | PackedN(_) | Packed => {
Err(UnsupportedReprError)
}
},
UnsupportedReprError,
)
.map(CompoundRepr::Primitive)
.map_err(FromRawReprError::Err)
}
Transparent | Align(_) | PackedN(_) | Packed => Err(FromRawReprError::None),
}
}
}
impl<Pcked: With<NonZeroU32>> TryFrom<RawRepr> for AlignRepr<Pcked> {
type Error = FromRawReprError<UnsupportedReprError>;
fn try_from(raw: RawRepr) -> Result<AlignRepr<Pcked>, FromRawReprError<UnsupportedReprError>> {
use RawRepr::*;
match raw {
Packed | PackedN(_) => Pcked::try_with_or(
|| match raw {
Packed => Ok(NonZeroU32::new(1).unwrap()),
PackedN(n) => Ok(n),
U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize
| Transparent | C | Rust | Align(_) => Err(UnsupportedReprError),
},
UnsupportedReprError,
)
.map(AlignRepr::Packed)
.map_err(FromRawReprError::Err),
Align(n) => Ok(AlignRepr::Align(n)),
U8 | U16 | U32 | U64 | U128 | Usize | I8 | I16 | I32 | I64 | I128 | Isize
| Transparent | C | Rust => Err(FromRawReprError::None),
}
}
}
/// The error from extracting a high-level repr type from a list of `RawRepr`s.
#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
enum FromRawReprsError<E> {
/// One of the `RawRepr`s is invalid for the high-level repr we're parsing
/// (e.g. there's a `packed` repr and we're parsing an `AlignRepr` for an
/// enum type).
Single(E),
/// Two `RawRepr`s appear which both affect the high-level repr we're
/// parsing (e.g., the list is `#[repr(align(2), packed)]`). Note that we
/// conservatively treat redundant reprs as conflicting (e.g.
/// `#[repr(packed, packed)]`).
Conflict,
}
/// Tries to extract a high-level repr from a list of `RawRepr`s.
fn try_from_raw_reprs<'a, E, R: TryFrom<RawRepr, Error = FromRawReprError<E>>>(
r: impl IntoIterator<Item = &'a Spanned<RawRepr>>,
) -> Result<Option<Spanned<R>>, Spanned<FromRawReprsError<E>>> {
// Walk the list of `RawRepr`s and attempt to convert each to an `R`. Bail
// if we find any errors. If we find more than one which converts to an `R`,
// bail with a `Conflict` error.
r.into_iter().try_fold(None, |found: Option<Spanned<R>>, raw| {
let new = match Spanned::<R>::try_from(*raw) {
Ok(r) => r,
// This `RawRepr` doesn't convert to an `R`, so keep the current
// found `R`, if any.
Err(FromRawReprError::None) => return Ok(found),
// This repr is unsupported for the decorated type (e.g.
// `repr(packed)` on an enum).
Err(FromRawReprError::Err(Spanned { t: err, span })) => {
return Err(Spanned::new(FromRawReprsError::Single(err), span))
}
};
if let Some(found) = found {
// We already found an `R`, but this `RawRepr` also converts to an
// `R`, so that's a conflict.
//
// `Span::join` returns `None` if the two spans are from different
// files or if we're not on the nightly compiler. In that case, just
// use `new`'s span.
let span = found.span.join(new.span).unwrap_or(new.span);
Err(Spanned::new(FromRawReprsError::Conflict, span))
} else {
Ok(Some(new))
}
})
}
/// The error returned from [`Repr::from_attrs`].
#[cfg_attr(test, derive(Copy, Clone, Debug, Eq, PartialEq))]
enum FromAttrsError {
FromRawReprs(FromRawReprsError<UnsupportedReprError>),
Unrecognized,
}
impl From<FromRawReprsError<UnsupportedReprError>> for FromAttrsError {
fn from(err: FromRawReprsError<UnsupportedReprError>) -> FromAttrsError {
FromAttrsError::FromRawReprs(err)
}
}
impl From<UnrecognizedReprError> for FromAttrsError {
fn from(_err: UnrecognizedReprError) -> FromAttrsError {
FromAttrsError::Unrecognized
}
}
impl From<Spanned<FromAttrsError>> for Error {
fn from(err: Spanned<FromAttrsError>) -> Error {
let Spanned { t: err, span } = err;
match err {
FromAttrsError::FromRawReprs(FromRawReprsError::Single(
_err @ UnsupportedReprError,
)) => Error::new(span, "unsupported representation hint for the decorated type"),
FromAttrsError::FromRawReprs(FromRawReprsError::Conflict) => {
// NOTE: This says "another" rather than "a preceding" because
// when one of the reprs involved is `transparent`, we detect
// that condition in `Repr::from_attrs`, and at that point we
// can't tell which repr came first, so we might report this on
// the first involved repr rather than the second, third, etc.
Error::new(span, "this conflicts with another representation hint")
}
FromAttrsError::Unrecognized => Error::new(span, "unrecognized representation hint"),
}
}
}
impl<Prim, Packed> Repr<Prim, Packed> {
fn from_attrs_inner(attrs: &[Attribute]) -> Result<Repr<Prim, Packed>, Spanned<FromAttrsError>>
where
Prim: With<PrimitiveRepr>,
Packed: With<NonZeroU32>,
{
let raw_reprs = RawRepr::from_attrs(attrs).map_err(Spanned::from)?;
let transparent = {
let mut transparents = raw_reprs.iter().filter_map(|Spanned { t, span }| match t {
RawRepr::Transparent => Some(span),
_ => None,
});
let first = transparents.next();
let second = transparents.next();
match (first, second) {
(None, None) => None,
(Some(span), None) => Some(*span),
(Some(_), Some(second)) => {
return Err(Spanned::new(
FromAttrsError::FromRawReprs(FromRawReprsError::Conflict),
*second,
))
}
// An iterator can't produce a value only on the second call to
// `.next()`.
(None, Some(_)) => unreachable!(),
}
};
let compound: Option<Spanned<CompoundRepr<Prim>>> =
try_from_raw_reprs(raw_reprs.iter()).map_err(Spanned::from)?;
let align: Option<Spanned<AlignRepr<Packed>>> =
try_from_raw_reprs(raw_reprs.iter()).map_err(Spanned::from)?;
if let Some(span) = transparent {
if compound.is_some() || align.is_some() {
// Arbitrarily report the problem on the `transparent` span. Any
// span will do.
return Err(Spanned::new(FromRawReprsError::Conflict.into(), span));
}
Ok(Repr::Transparent(span))
} else {
Ok(Repr::Compound(
compound.unwrap_or(Spanned::new(CompoundRepr::Rust, Span::call_site())),
align,
))
}
}
}
impl<Prim, Packed> Repr<Prim, Packed> {
pub(crate) fn from_attrs(attrs: &[Attribute]) -> Result<Repr<Prim, Packed>, Error>
where
Prim: With<PrimitiveRepr>,
Packed: With<NonZeroU32>,
{
Repr::from_attrs_inner(attrs).map_err(Into::into)
}
}
/// The representation hint could not be parsed or was unrecognized.
struct UnrecognizedReprError;
impl RawRepr {
fn from_attrs(
attrs: &[Attribute],
) -> Result<Vec<Spanned<RawRepr>>, Spanned<UnrecognizedReprError>> {
let mut reprs = 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(_) => {
return Err(Spanned::new(
UnrecognizedReprError,
meta_list.tokens.span(),
))
}
};
for meta in parsed {
let s = meta.span();
reprs.push(
RawRepr::from_meta(&meta)
.map(|r| Spanned::new(r, s))
.map_err(|e| Spanned::new(e, s))?,
);
}
}
}
}
Ok(reprs)
}
fn from_meta(meta: &Meta) -> Result<RawRepr, UnrecognizedReprError> {
let (path, list) = match meta {
Meta::Path(path) => (path, None),
Meta::List(list) => (&list.path, Some(list)),
_ => return Err(UnrecognizedReprError),
};
let ident = path.get_ident().ok_or(UnrecognizedReprError)?;
// Only returns `Ok` for non-zero power-of-two values.
let parse_nzu64 = |list: &MetaList| {
list.parse_args::<LitInt>()
.and_then(|int| int.base10_parse::<NonZeroU32>())
.map_err(|_| UnrecognizedReprError)
.and_then(|nz| {
if nz.get().is_power_of_two() {
Ok(nz)
} else {
Err(UnrecognizedReprError)
}
})
};
use RawRepr::*;
Ok(match (ident.to_string().as_str(), list) {
("u8", None) => U8,
("u16", None) => U16,
("u32", None) => U32,
("u64", None) => U64,
("u128", None) => U128,
("usize", None) => Usize,
("i8", None) => I8,
("i16", None) => I16,
("i32", None) => I32,
("i64", None) => I64,
("i128", None) => I128,
("isize", None) => Isize,
("C", None) => C,
("transparent", None) => Transparent,
("Rust", None) => Rust,
("packed", None) => Packed,
("packed", Some(list)) => PackedN(parse_nzu64(list)?),
("align", Some(list)) => Align(parse_nzu64(list)?),
_ => return Err(UnrecognizedReprError),
})
}
}
pub(crate) use util::*;
mod util {
use super::*;
/// A value with an associated span.
#[derive(Copy, Clone)]
#[cfg_attr(test, derive(Debug))]
pub(crate) struct Spanned<T> {
pub(crate) t: T,
pub(crate) span: Span,
}
impl<T> Spanned<T> {
pub(super) fn new(t: T, span: Span) -> Spanned<T> {
Spanned { t, span }
}
pub(super) fn from<U>(s: Spanned<U>) -> Spanned<T>
where
T: From<U>,
{
let Spanned { t: u, span } = s;
Spanned::new(u.into(), span)
}
/// Delegates to `T: TryFrom`, preserving span information in both the
/// success and error cases.
pub(super) fn try_from<E, U>(
u: Spanned<U>,
) -> Result<Spanned<T>, FromRawReprError<Spanned<E>>>
where
T: TryFrom<U, Error = FromRawReprError<E>>,
{
let Spanned { t: u, span } = u;
T::try_from(u).map(|t| Spanned { t, span }).map_err(|err| match err {
FromRawReprError::None => FromRawReprError::None,
FromRawReprError::Err(e) => FromRawReprError::Err(Spanned::new(e, span)),
})
}
}
// Used to permit implementing `With<T> for T: Inhabited` and for
// `Infallible` without a blanket impl conflict.
pub(crate) trait Inhabited {}
impl Inhabited for PrimitiveRepr {}
impl Inhabited for NonZeroU32 {}
pub(crate) trait With<T> {
fn with<O, F: FnOnce(T) -> O>(self, f: F) -> O;
fn try_with_or<E, F: FnOnce() -> Result<T, E>>(f: F, err: E) -> Result<Self, E>
where
Self: Sized;
}
impl<T: Inhabited> With<T> for T {
fn with<O, F: FnOnce(T) -> O>(self, f: F) -> O {
f(self)
}
fn try_with_or<E, F: FnOnce() -> Result<T, E>>(f: F, _err: E) -> Result<Self, E> {
f()
}
}
impl<T> With<T> for Infallible {
fn with<O, F: FnOnce(T) -> O>(self, _f: F) -> O {
match self {}
}
fn try_with_or<E, F: FnOnce() -> Result<T, E>>(_f: F, err: E) -> Result<Self, E> {
Err(err)
}
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::*;
impl<T> From<T> for Spanned<T> {
fn from(t: T) -> Spanned<T> {
Spanned::new(t, Span::call_site())
}
}
// We ignore spans for equality in testing since real spans are hard to
// synthesize and don't implement `PartialEq`.
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Spanned<T>) -> bool {
self.t.eq(&other.t)
}
}
impl<T: Eq> Eq for Spanned<T> {}
impl<Prim: PartialEq, Packed: PartialEq> PartialEq for Repr<Prim, Packed> {
fn eq(&self, other: &Repr<Prim, Packed>) -> bool {
match (self, other) {
(Repr::Transparent(_), Repr::Transparent(_)) => true,
(Repr::Compound(sc, sa), Repr::Compound(oc, oa)) => (sc, sa) == (oc, oa),
_ => false,
}
}
}
fn s() -> Span {
Span::call_site()
}
#[test]
fn test() {
// Test that a given `#[repr(...)]` attribute parses and returns the
// given `Repr` or error.
macro_rules! test {
($(#[$attr:meta])* => $repr:expr) => {
test!(@inner $(#[$attr])* => Repr => Ok($repr));
};
// In the error case, the caller must explicitly provide the name of
// the `Repr` type to assist in type inference.
(@error $(#[$attr:meta])* => $typ:ident => $repr:expr) => {
test!(@inner $(#[$attr])* => $typ => Err($repr));
};
(@inner $(#[$attr:meta])* => $typ:ident => $repr:expr) => {
let attr: Attribute = parse_quote!($(#[$attr])*);
let mut got = $typ::from_attrs_inner(&[attr]);
let expect: Result<Repr<_, _>, _> = $repr;
if false {
// Force Rust to infer `got` as having the same type as
// `expect`.
got = expect;
}
assert_eq!(got, expect, stringify!($(#[$attr])*));
};
}
use AlignRepr::*;
use CompoundRepr::*;
use PrimitiveRepr::*;
let nz = |n: u32| NonZeroU32::new(n).unwrap();
test!(#[repr(transparent)] => StructUnionRepr::Transparent(s()));
test!(#[repr()] => StructUnionRepr::Compound(Rust.into(), None));
test!(#[repr(packed)] => StructUnionRepr::Compound(Rust.into(), Some(Packed(nz(1)).into())));
test!(#[repr(packed(2))] => StructUnionRepr::Compound(Rust.into(), Some(Packed(nz(2)).into())));
test!(#[repr(align(1))] => StructUnionRepr::Compound(Rust.into(), Some(Align(nz(1)).into())));
test!(#[repr(align(2))] => StructUnionRepr::Compound(Rust.into(), Some(Align(nz(2)).into())));
test!(#[repr(C)] => StructUnionRepr::Compound(C.into(), None));
test!(#[repr(C, packed)] => StructUnionRepr::Compound(C.into(), Some(Packed(nz(1)).into())));
test!(#[repr(C, packed(2))] => StructUnionRepr::Compound(C.into(), Some(Packed(nz(2)).into())));
test!(#[repr(C, align(1))] => StructUnionRepr::Compound(C.into(), Some(Align(nz(1)).into())));
test!(#[repr(C, align(2))] => StructUnionRepr::Compound(C.into(), Some(Align(nz(2)).into())));
test!(#[repr(transparent)] => EnumRepr::Transparent(s()));
test!(#[repr()] => EnumRepr::Compound(Rust.into(), None));
test!(#[repr(align(1))] => EnumRepr::Compound(Rust.into(), Some(Align(nz(1)).into())));
test!(#[repr(align(2))] => EnumRepr::Compound(Rust.into(), Some(Align(nz(2)).into())));
macro_rules! for_each_compound_repr {
($($r:tt => $var:expr),*) => {
$(
test!(#[repr($r)] => EnumRepr::Compound($var.into(), None));
test!(#[repr($r, align(1))] => EnumRepr::Compound($var.into(), Some(Align(nz(1)).into())));
test!(#[repr($r, align(2))] => EnumRepr::Compound($var.into(), Some(Align(nz(2)).into())));
)*
}
}
for_each_compound_repr!(
C => C,
u8 => Primitive(U8),
u16 => Primitive(U16),
u32 => Primitive(U32),
u64 => Primitive(U64),
usize => Primitive(Usize),
i8 => Primitive(I8),
i16 => Primitive(I16),
i32 => Primitive(I32),
i64 => Primitive(I64),
isize => Primitive(Isize)
);
use FromAttrsError::*;
use FromRawReprsError::*;
// Run failure tests which are valid for both `StructUnionRepr` and
// `EnumRepr`.
macro_rules! for_each_repr_type {
($($repr:ident),*) => {
$(
// Invalid packed or align attributes
test!(@error #[repr(packed(0))] => $repr => Unrecognized.into());
test!(@error #[repr(packed(3))] => $repr => Unrecognized.into());
test!(@error #[repr(align(0))] => $repr => Unrecognized.into());
test!(@error #[repr(align(3))] => $repr => Unrecognized.into());
// Conflicts
test!(@error #[repr(transparent, transparent)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(transparent, C)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(transparent, Rust)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(C, transparent)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(C, C)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(C, Rust)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(Rust, transparent)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(Rust, C)] => $repr => FromRawReprs(Conflict).into());
test!(@error #[repr(Rust, Rust)] => $repr => FromRawReprs(Conflict).into());
)*
}
}
for_each_repr_type!(StructUnionRepr, EnumRepr);
// Enum-specific conflicts.
//
// We don't bother to test every combination since that would be a huge
// number (enums can have primitive reprs u8, u16, u32, u64, usize, i8,
// i16, i32, i64, and isize). Instead, since the conflict logic doesn't
// care what specific value of `PrimitiveRepr` is present, we assume
// that testing against u8 alone is fine.
test!(@error #[repr(transparent, u8)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(u8, transparent)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(C, u8)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(u8, C)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(Rust, u8)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(u8, Rust)] => EnumRepr => FromRawReprs(Conflict).into());
test!(@error #[repr(u8, u8)] => EnumRepr => FromRawReprs(Conflict).into());
// Illegal struct/union reprs
test!(@error #[repr(u8)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(u16)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(u32)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(u64)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(usize)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(i8)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(i16)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(i32)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(i64)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(isize)] => StructUnionRepr => FromRawReprs(Single(UnsupportedReprError)).into());
// Illegal enum reprs
test!(@error #[repr(packed)] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(packed(1))] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
test!(@error #[repr(packed(2))] => EnumRepr => FromRawReprs(Single(UnsupportedReprError)).into());
}
}

843
vendor/zerocopy-derive/src/util.rs vendored Normal file
View File

@@ -0,0 +1,843 @@
// 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 std::num::NonZeroU32;
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens};
use syn::{
parse_quote, spanned::Spanned as _, Data, DataEnum, DataStruct, DataUnion, DeriveInput, Error,
Expr, ExprLit, Field, GenericParam, Ident, Index, Lit, LitStr, Meta, Path, Type, Variant,
Visibility, WherePredicate,
};
use crate::repr::{CompoundRepr, EnumRepr, PrimitiveRepr, Repr, Spanned};
pub(crate) struct Ctx {
pub(crate) ast: DeriveInput,
pub(crate) zerocopy_crate: Path,
// The value of the last `#[zerocopy(on_error = ...)]` attribute, or `false`
// if none is provided.
pub(crate) skip_on_error: bool,
// The span of the last `#[zerocopy(on_error = ...)]` attribute, if any.
pub(crate) on_error_span: Option<proc_macro2::Span>,
}
impl Ctx {
/// Attempt to extract a crate path from the provided attributes. Defaults to
/// `::zerocopy` if not found.
pub(crate) fn try_from_derive_input(ast: DeriveInput) -> Result<Self, Error> {
let mut path = parse_quote!(::zerocopy);
let mut skip_on_error = false;
let mut on_error_span = None;
for attr in &ast.attrs {
if let Meta::List(ref meta_list) = attr.meta {
if meta_list.path.is_ident("zerocopy") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("crate") {
let expr = meta.value().and_then(|value| value.parse());
if let Ok(Expr::Lit(ExprLit { lit: Lit::Str(lit), .. })) = expr {
if let Ok(path_lit) = lit.parse::<Ident>() {
path = parse_quote!(::#path_lit);
return Ok(());
}
}
return Err(Error::new(
Span::call_site(),
"`crate` attribute requires a path as the value",
));
}
if meta.path.is_ident("on_error") {
on_error_span = Some(meta.path.span());
let value = meta.value()?;
let s: LitStr = value.parse()?;
match s.value().as_str() {
"skip" => skip_on_error = true,
"fail" => skip_on_error = false,
_ => return Err(Error::new(
s.span(),
"unrecognized value for `on_error` attribute from `zerocopy`; expected `skip` or `fail`",
)),
}
return Ok(());
}
Err(Error::new(
Span::call_site(),
format!(
"unknown attribute encountered: {}",
meta.path.into_token_stream()
),
))
})?;
}
}
}
Ok(Self { ast, zerocopy_crate: path, skip_on_error, on_error_span })
}
pub(crate) fn with_input(&self, input: &DeriveInput) -> Self {
Self {
ast: input.clone(),
zerocopy_crate: self.zerocopy_crate.clone(),
skip_on_error: self.skip_on_error,
on_error_span: self.on_error_span,
}
}
pub(crate) fn core_path(&self) -> TokenStream {
let zerocopy_crate = &self.zerocopy_crate;
quote!(#zerocopy_crate::util::macro_util::core_reexport)
}
pub(crate) fn cfg_compile_error(&self) -> TokenStream {
// By checking both during the compilation of the proc macro *and* in
// the generated code, we ensure that `--cfg
// zerocopy_unstable_derive_on_error` need only be passed *either* when
// compiling this crate *or* when compiling the user's crate. The former
// is preferable, but in some situations (such as when cross-compiling
// using `cargo build --target`), it doesn't get propagated to this
// crate's build by default.
if cfg!(zerocopy_unstable_derive_on_error) {
quote!()
} else if let Some(span) = self.on_error_span {
let core = self.core_path();
let error_message = "`on_error` is experimental; pass '--cfg zerocopy_unstable_derive_on_error' to enable";
quote::quote_spanned! {span=>
#[allow(unused_attributes, unexpected_cfgs)]
const _: () = {
#[cfg(not(zerocopy_unstable_derive_on_error))]
#core::compile_error!(#error_message);
};
}
} else {
quote!()
}
}
pub(crate) fn error_or_skip<E>(&self, error: E) -> Result<TokenStream, E> {
if self.skip_on_error {
Ok(self.cfg_compile_error())
} else {
Err(error)
}
}
}
pub(crate) trait DataExt {
/// Extracts the names and types of all fields. For enums, extracts the
/// names and types of fields from each variant. For tuple structs, the
/// names are the indices used to index into the struct (ie, `0`, `1`, etc).
///
/// FIXME: Extracting field names for enums doesn't really make sense. Types
/// makes sense because we don't care about where they live - we just care
/// about transitive ownership. But for field names, we'd only use them when
/// generating is_bit_valid, which cares about where they live.
fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>;
fn variants(&self) -> Vec<(Option<&Variant>, Vec<(&Visibility, TokenStream, &Type)>)>;
fn tag(&self) -> Option<Ident>;
}
impl DataExt for Data {
fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
match self {
Data::Struct(strc) => strc.fields(),
Data::Enum(enm) => enm.fields(),
Data::Union(un) => un.fields(),
}
}
fn variants(&self) -> Vec<(Option<&Variant>, Vec<(&Visibility, TokenStream, &Type)>)> {
match self {
Data::Struct(strc) => strc.variants(),
Data::Enum(enm) => enm.variants(),
Data::Union(un) => un.variants(),
}
}
fn tag(&self) -> Option<Ident> {
match self {
Data::Struct(strc) => strc.tag(),
Data::Enum(enm) => enm.tag(),
Data::Union(un) => un.tag(),
}
}
}
impl DataExt for DataStruct {
fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
map_fields(&self.fields)
}
fn variants(&self) -> Vec<(Option<&Variant>, Vec<(&Visibility, TokenStream, &Type)>)> {
vec![(None, self.fields())]
}
fn tag(&self) -> Option<Ident> {
None
}
}
impl DataExt for DataEnum {
fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
map_fields(self.variants.iter().flat_map(|var| &var.fields))
}
fn variants(&self) -> Vec<(Option<&Variant>, Vec<(&Visibility, TokenStream, &Type)>)> {
self.variants.iter().map(|var| (Some(var), map_fields(&var.fields))).collect()
}
fn tag(&self) -> Option<Ident> {
Some(Ident::new("___ZerocopyTag", Span::call_site()))
}
}
impl DataExt for DataUnion {
fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
map_fields(&self.fields.named)
}
fn variants(&self) -> Vec<(Option<&Variant>, Vec<(&Visibility, TokenStream, &Type)>)> {
vec![(None, self.fields())]
}
fn tag(&self) -> Option<Ident> {
None
}
}
fn map_fields<'a>(
fields: impl 'a + IntoIterator<Item = &'a Field>,
) -> Vec<(&'a Visibility, TokenStream, &'a Type)> {
fields
.into_iter()
.enumerate()
.map(|(idx, f)| {
(
&f.vis,
f.ident
.as_ref()
.map(ToTokens::to_token_stream)
.unwrap_or_else(|| Index::from(idx).to_token_stream()),
&f.ty,
)
})
.collect()
}
pub(crate) fn to_ident_str(t: &impl ToString) -> String {
let s = t.to_string();
if let Some(stripped) = s.strip_prefix("r#") {
stripped.to_string()
} else {
s
}
}
/// This enum describes what kind of padding check needs to be generated for the
/// associated impl.
pub(crate) enum PaddingCheck {
/// Check that the sum of the fields' sizes exactly equals the struct's
/// size.
Struct,
/// Check that a `repr(C)` struct has no padding.
ReprCStruct,
/// Check that the size of each field exactly equals the union's size.
Union,
/// Check that every variant of the enum contains no padding.
///
/// Because doing so requires a tag enum, this padding check requires an
/// additional `TokenStream` which defines the tag enum as `___ZerocopyTag`.
Enum { tag_type_definition: TokenStream },
}
impl PaddingCheck {
/// Returns the idents of the trait to use and the macro to call in order to
/// validate that a type passes the relevant padding check.
pub(crate) fn validator_trait_and_macro_idents(&self) -> (Ident, Ident) {
let (trt, mcro) = match self {
PaddingCheck::Struct => ("PaddingFree", "struct_padding"),
PaddingCheck::ReprCStruct => ("DynamicPaddingFree", "repr_c_struct_has_padding"),
PaddingCheck::Union => ("PaddingFree", "union_padding"),
PaddingCheck::Enum { .. } => ("PaddingFree", "enum_padding"),
};
let trt = Ident::new(trt, Span::call_site());
let mcro = Ident::new(mcro, Span::call_site());
(trt, mcro)
}
/// Sometimes performing the padding check requires some additional
/// "context" code. For enums, this is the definition of the tag enum.
pub(crate) fn validator_macro_context(&self) -> Option<&TokenStream> {
match self {
PaddingCheck::Struct | PaddingCheck::ReprCStruct | PaddingCheck::Union => None,
PaddingCheck::Enum { tag_type_definition } => Some(tag_type_definition),
}
}
}
#[derive(Clone)]
pub(crate) enum Trait {
KnownLayout,
HasTag,
HasField {
variant_id: Box<Expr>,
field: Box<Type>,
field_id: Box<Expr>,
},
ProjectField {
variant_id: Box<Expr>,
field: Box<Type>,
field_id: Box<Expr>,
invariants: Box<Type>,
},
Immutable,
TryFromBytes,
FromZeros,
FromBytes,
IntoBytes,
Unaligned,
Sized,
ByteHash,
ByteEq,
SplitAt,
}
impl ToTokens for Trait {
fn to_tokens(&self, tokens: &mut TokenStream) {
// According to [1], the format of the derived `Debug`` output is not
// stable and therefore not guaranteed to represent the variant names.
// Indeed with the (unstable) `fmt-debug` compiler flag [2], it can
// return only a minimalized output or empty string. To make sure this
// code will work in the future and independent of the compiler flag, we
// translate the variants to their names manually here.
//
// [1] https://doc.rust-lang.org/1.81.0/std/fmt/trait.Debug.html#stability
// [2] https://doc.rust-lang.org/beta/unstable-book/compiler-flags/fmt-debug.html
let s = match self {
Trait::HasField { .. } => "HasField",
Trait::ProjectField { .. } => "ProjectField",
Trait::KnownLayout => "KnownLayout",
Trait::HasTag => "HasTag",
Trait::Immutable => "Immutable",
Trait::TryFromBytes => "TryFromBytes",
Trait::FromZeros => "FromZeros",
Trait::FromBytes => "FromBytes",
Trait::IntoBytes => "IntoBytes",
Trait::Unaligned => "Unaligned",
Trait::Sized => "Sized",
Trait::ByteHash => "ByteHash",
Trait::ByteEq => "ByteEq",
Trait::SplitAt => "SplitAt",
};
let ident = Ident::new(s, Span::call_site());
let arguments: Option<syn::AngleBracketedGenericArguments> = match self {
Trait::HasField { variant_id, field, field_id } => {
Some(parse_quote!(<#field, #variant_id, #field_id>))
}
Trait::ProjectField { variant_id, field, field_id, invariants } => {
Some(parse_quote!(<#field, #invariants, #variant_id, #field_id>))
}
Trait::KnownLayout
| Trait::HasTag
| Trait::Immutable
| Trait::TryFromBytes
| Trait::FromZeros
| Trait::FromBytes
| Trait::IntoBytes
| Trait::Unaligned
| Trait::Sized
| Trait::ByteHash
| Trait::ByteEq
| Trait::SplitAt => None,
};
tokens.extend(quote!(#ident #arguments));
}
}
impl Trait {
pub(crate) fn crate_path(&self, ctx: &Ctx) -> Path {
let zerocopy_crate = &ctx.zerocopy_crate;
let core = ctx.core_path();
match self {
Self::Sized => parse_quote!(#core::marker::#self),
_ => parse_quote!(#zerocopy_crate::#self),
}
}
}
pub(crate) enum TraitBound {
Slf,
Other(Trait),
}
pub(crate) enum FieldBounds<'a> {
None,
All(&'a [TraitBound]),
Trailing(&'a [TraitBound]),
Explicit(Vec<WherePredicate>),
}
impl<'a> FieldBounds<'a> {
pub(crate) const ALL_SELF: FieldBounds<'a> = FieldBounds::All(&[TraitBound::Slf]);
pub(crate) const TRAILING_SELF: FieldBounds<'a> = FieldBounds::Trailing(&[TraitBound::Slf]);
}
pub(crate) enum SelfBounds<'a> {
None,
All(&'a [Trait]),
}
// FIXME(https://github.com/rust-lang/rust-clippy/issues/12908): This is a false
// positive. Explicit lifetimes are actually necessary here.
#[allow(clippy::needless_lifetimes)]
impl<'a> SelfBounds<'a> {
pub(crate) const SIZED: Self = Self::All(&[Trait::Sized]);
}
/// Normalizes a slice of bounds by replacing [`TraitBound::Slf`] with `slf`.
pub(crate) fn normalize_bounds<'a>(
slf: &'a Trait,
bounds: &'a [TraitBound],
) -> impl 'a + Iterator<Item = Trait> {
bounds.iter().map(move |bound| match bound {
TraitBound::Slf => slf.clone(),
TraitBound::Other(trt) => trt.clone(),
})
}
pub(crate) struct ImplBlockBuilder<'a> {
ctx: &'a Ctx,
data: &'a dyn DataExt,
trt: Trait,
field_type_trait_bounds: FieldBounds<'a>,
self_type_trait_bounds: SelfBounds<'a>,
padding_check: Option<PaddingCheck>,
param_extras: Vec<GenericParam>,
inner_extras: Option<TokenStream>,
outer_extras: Option<TokenStream>,
}
impl<'a> ImplBlockBuilder<'a> {
pub(crate) fn new(
ctx: &'a Ctx,
data: &'a dyn DataExt,
trt: Trait,
field_type_trait_bounds: FieldBounds<'a>,
) -> Self {
Self {
ctx,
data,
trt,
field_type_trait_bounds,
self_type_trait_bounds: SelfBounds::None,
padding_check: None,
param_extras: Vec::new(),
inner_extras: None,
outer_extras: None,
}
}
pub(crate) fn self_type_trait_bounds(mut self, self_type_trait_bounds: SelfBounds<'a>) -> Self {
self.self_type_trait_bounds = self_type_trait_bounds;
self
}
pub(crate) fn padding_check<P: Into<Option<PaddingCheck>>>(mut self, padding_check: P) -> Self {
self.padding_check = padding_check.into();
self
}
pub(crate) fn param_extras(mut self, param_extras: Vec<GenericParam>) -> Self {
self.param_extras.extend(param_extras);
self
}
pub(crate) fn inner_extras(mut self, inner_extras: TokenStream) -> Self {
self.inner_extras = Some(inner_extras);
self
}
pub(crate) fn outer_extras<T: Into<Option<TokenStream>>>(mut self, outer_extras: T) -> Self {
self.outer_extras = outer_extras.into();
self
}
pub(crate) fn build(self) -> 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 = &self.ctx.ast.ident;
let trait_path = self.trt.crate_path(self.ctx);
let fields = self.data.fields();
let variants = self.data.variants();
let tag = self.data.tag();
let zerocopy_crate = &self.ctx.zerocopy_crate;
fn bound_tt(ty: &Type, traits: impl Iterator<Item = Trait>, ctx: &Ctx) -> WherePredicate {
let traits = traits.map(|t| t.crate_path(ctx));
parse_quote!(#ty: #(#traits)+*)
}
let field_type_bounds: Vec<_> = match (self.field_type_trait_bounds, &fields[..]) {
(FieldBounds::All(traits), _) => fields
.iter()
.map(|(_vis, _name, ty)| {
bound_tt(ty, normalize_bounds(&self.trt, traits), self.ctx)
})
.collect(),
(FieldBounds::None, _) | (FieldBounds::Trailing(..), []) => vec![],
(FieldBounds::Trailing(traits), [.., last]) => {
vec![bound_tt(last.2, normalize_bounds(&self.trt, traits), self.ctx)]
}
(FieldBounds::Explicit(bounds), _) => bounds,
};
let padding_check_bound = self
.padding_check
.map(|check| {
// Parse the repr for `align` and `packed` modifiers. Note that
// `Repr::<PrimitiveRepr, NonZeroU32>` is more permissive than
// what Rust supports for structs, enums, or unions, and thus
// reliably extracts these modifiers for any kind of type.
let repr =
Repr::<PrimitiveRepr, NonZeroU32>::from_attrs(&self.ctx.ast.attrs).unwrap();
let core = self.ctx.core_path();
let option = quote! { #core::option::Option };
let nonzero = quote! { #core::num::NonZeroUsize };
let none = quote! { #option::None::<#nonzero> };
let repr_align =
repr.get_align().map(|spanned| {
let n = spanned.t.get();
quote_spanned! { spanned.span => (#nonzero::new(#n as usize)) }
}).unwrap_or(quote! { (#none) });
let repr_packed =
repr.get_packed().map(|packed| {
let n = packed.get();
quote! { (#nonzero::new(#n as usize)) }
}).unwrap_or(quote! { (#none) });
let variant_types = variants.iter().map(|(_, fields)| {
let types = fields.iter().map(|(_vis, _name, ty)| ty);
quote!([#((#types)),*])
});
let validator_context = check.validator_macro_context();
let (trt, validator_macro) = check.validator_trait_and_macro_idents();
let t = tag.iter();
parse_quote! {
(): #zerocopy_crate::util::macro_util::#trt<
Self,
{
#validator_context
#zerocopy_crate::#validator_macro!(Self, #repr_align, #repr_packed, #(#t,)* #(#variant_types),*)
}
>
}
});
let self_bounds: Option<WherePredicate> = match self.self_type_trait_bounds {
SelfBounds::None => None,
SelfBounds::All(traits) => {
Some(bound_tt(&parse_quote!(Self), traits.iter().cloned(), self.ctx))
}
};
let bounds = self
.ctx
.ast
.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_bounds.iter());
// The parameters with trait bounds, but without type defaults.
let mut params: Vec<_> = self
.ctx
.ast
.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(_) => {}
}
parse_quote!(#param)
})
.chain(self.param_extras)
.collect();
// For MSRV purposes, ensure that lifetimes precede types precede const
// generics.
params.sort_by_cached_key(|param| match param {
GenericParam::Lifetime(_) => 0,
GenericParam::Type(_) => 1,
GenericParam::Const(_) => 2,
});
// The identifiers of the parameters without trait bounds or type
// defaults.
let param_idents = self.ctx.ast.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})
}
});
let inner_extras = self.inner_extras;
let allow_trivial_bounds =
if self.ctx.skip_on_error { quote!(#[allow(trivial_bounds)]) } else { quote!() };
let impl_tokens = quote! {
#allow_trivial_bounds
unsafe impl < #(#params),* > #trait_path for #type_ident < #(#param_idents),* >
where
#(#bounds,)*
{
fn only_derive_is_allowed_to_implement_this_trait() {}
#inner_extras
}
};
let outer_extras = self.outer_extras.filter(|e| !e.is_empty());
let cfg_compile_error = self.ctx.cfg_compile_error();
const_block([Some(cfg_compile_error), Some(impl_tokens), outer_extras])
}
}
// A polyfill for `Option::then_some`, which was added after our MSRV.
//
// The `#[allow(unused)]` is necessary because, on sufficiently recent toolchain
// versions, `b.then_some(...)` resolves to the inherent method rather than to
// this trait, and so this trait is considered unused.
//
// FIXME(#67): Remove this once our MSRV is >= 1.62.
#[allow(unused)]
trait BoolExt {
fn then_some<T>(self, t: T) -> Option<T>;
}
impl BoolExt for bool {
fn then_some<T>(self, t: T) -> Option<T> {
if self {
Some(t)
} else {
None
}
}
}
pub(crate) fn const_block(items: impl IntoIterator<Item = Option<TokenStream>>) -> TokenStream {
let items = items.into_iter().flatten();
quote! {
#[allow(
// FIXME(#553): Add a test that generates a warning when
// `#[allow(deprecated)]` isn't present.
deprecated,
// Required on some rustc versions due to a lint that is only
// triggered when `derive(KnownLayout)` is applied to `repr(C)`
// structs that are generated by macros. See #2177 for details.
private_bounds,
non_local_definitions,
non_camel_case_types,
non_upper_case_globals,
non_snake_case,
non_ascii_idents,
clippy::missing_inline_in_public_items,
)]
#[deny(ambiguous_associated_items)]
// While there are not currently any warnings that this suppresses
// (that we're aware of), it's good future-proofing hygiene.
#[automatically_derived]
const _: () = {
#(#items)*
};
}
}
pub(crate) fn generate_tag_enum(ctx: &Ctx, repr: &EnumRepr, data: &DataEnum) -> TokenStream {
let zerocopy_crate = &ctx.zerocopy_crate;
let variants = data.variants.iter().map(|v| {
let ident = &v.ident;
if let Some((eq, discriminant)) = &v.discriminant {
quote! { #ident #eq #discriminant }
} else {
quote! { #ident }
}
});
// Don't include any `repr(align)` when generating the tag enum, as that
// could add padding after the tag but before any variants, which is not the
// correct behavior.
let repr = match repr {
EnumRepr::Transparent(span) => quote::quote_spanned! { *span => #[repr(transparent)] },
EnumRepr::Compound(c, _) => quote! { #c },
};
quote! {
#repr
#[allow(dead_code)]
pub enum ___ZerocopyTag {
#(#variants,)*
}
// SAFETY: `___ZerocopyTag` has no fields, and so it does not permit
// interior mutation.
unsafe impl #zerocopy_crate::Immutable for ___ZerocopyTag {
fn only_derive_is_allowed_to_implement_this_trait() {}
}
}
}
pub(crate) fn enum_size_from_repr(repr: &EnumRepr) -> Result<usize, Error> {
use CompoundRepr::*;
use PrimitiveRepr::*;
use Repr::*;
match repr {
Transparent(span)
| Compound(
Spanned {
t: C | Rust | Primitive(U32 | I32 | U64 | I64 | U128 | I128 | Usize | Isize),
span,
},
_,
) => Err(Error::new(
*span,
"`FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`",
)),
Compound(Spanned { t: Primitive(U8 | I8), span: _ }, _align) => Ok(8),
Compound(Spanned { t: Primitive(U16 | I16), span: _ }, _align) => Ok(16),
}
}
#[cfg(test)]
pub(crate) mod testutil {
use proc_macro2::TokenStream;
use syn::visit::{self, Visit};
/// Checks for hygiene violations in the generated code.
///
/// # Panics
///
/// Panics if a hygiene violation is found.
pub(crate) fn check_hygiene(ts: TokenStream) {
struct AmbiguousItemVisitor;
impl<'ast> Visit<'ast> for AmbiguousItemVisitor {
fn visit_path(&mut self, i: &'ast syn::Path) {
if i.segments.len() > 1 && i.segments.first().unwrap().ident == "Self" {
panic!(
"Found ambiguous path `{}` in generated output. \
All associated item access must be fully qualified (e.g., `<Self as Trait>::Item`) \
to prevent hygiene issues.",
quote::quote!(#i)
);
}
visit::visit_path(self, i);
}
}
let file = syn::parse2::<syn::File>(ts).expect("failed to parse generated output as File");
AmbiguousItemVisitor.visit_file(&file);
}
#[test]
fn test_check_hygiene_success() {
check_hygiene(quote::quote! {
fn foo() {
let _ = <Self as Trait>::Item;
}
});
}
#[test]
#[should_panic(expected = "Found ambiguous path `Self :: Ambiguous`")]
fn test_check_hygiene_failure() {
check_hygiene(quote::quote! {
fn foo() {
let _ = Self::Ambiguous;
}
});
}
}

View File

@@ -0,0 +1 @@
{"name":"zerocopy-derive","vers":"0.8.47","deps":[{"name":"proc-macro2","req":"^1.0.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"quote","req":"^1.0.40","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"syn","req":"^2.0.46","features":["full"],"optional":false,"default_features":true,"target":null,"kind":"normal","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"dissimilar","req":"^1.0.9","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"prettyplease","req":"=0.2.17","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"rustversion","req":"^1.0","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"static_assertions","req":"^1.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false},{"name":"syn","req":"^2.0.46","features":["visit"],"optional":false,"default_features":true,"target":null,"kind":"dev","registry":"https://github.com/rust-lang/crates.io-index","package":null,"public":null,"artifact":null,"bindep_target":null,"lib":false}],"features":{},"features2":null,"cksum":"4c1f53e9c198dbaa96e92f33f650a1828682bc791e69021794af7756ff617cb5","yanked":null,"links":null,"rust_version":null,"v":2}

Binary file not shown.

View File

@@ -0,0 +1,131 @@
// Copyright 2024 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
#![deny(deprecated)]
include!("include.rs");
// Make sure no deprecation warnings are generated from our derives (see #553).
#[macro_export]
macro_rules! test {
($name:ident => $ty:item => $($trait:ident),*) => {
#[allow(non_snake_case)]
mod $name {
$(
mod $trait {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::$trait)]
#[zerocopy(crate = "zerocopy_renamed")]
$ty
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!($name: imp::$trait);
}
}
)*
}
};
}
// NOTE: `FromBytes` is tested separately in `enum_from_bytes.rs` since it
// requires 256-variant enums which are extremely verbose; such enums are
// already in that file.
test!(Enum => #[repr(u8)] enum Enum { A, } => TryFromBytes, FromZeros, KnownLayout, Immutable, IntoBytes, Unaligned);
test!(Struct => #[repr(C)] struct Struct; => TryFromBytes, FromZeros, FromBytes, KnownLayout, Immutable, IntoBytes, Unaligned);
test!(Union => #[repr(C)] union Union{ a: (), } => TryFromBytes, FromZeros, FromBytes, KnownLayout, Immutable, IntoBytes, Unaligned);
// Tests for ByteHash and ByteEq which require IntoBytes + Immutable
mod enum_hash_eq {
mod ByteHash {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::ByteHash, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum Enum {
A,
}
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!(Enum: ::core::hash::Hash);
}
}
mod ByteEq {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::ByteEq, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum Enum {
A,
}
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!(Enum: ::core::cmp::PartialEq, ::core::cmp::Eq);
}
}
}
mod struct_hash_eq {
mod ByteHash {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::ByteHash, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct;
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!(Struct: ::core::hash::Hash);
}
}
mod ByteEq {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::ByteEq, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct;
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!(Struct: ::core::cmp::PartialEq, ::core::cmp::Eq);
}
}
}
// Tests for SplitAt which requires repr(C) and at least one field
mod split_at_test {
mod SplitAt {
use super::super::*;
#[deprecated = "do not use"]
#[derive(imp::SplitAt, imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct {
a: [u8],
}
#[allow(deprecated)]
fn _allow_deprecated() {
util_assert_impl_all!(Struct: imp::SplitAt);
}
}
}

View File

@@ -0,0 +1,108 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum Foo {
A,
}
util_assert_impl_all!(Foo: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum Bar {
A = 0,
}
util_assert_impl_all!(Bar: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum TwoVariantsHasExplicitZero {
A = 1,
B = 0,
}
util_assert_impl_all!(TwoVariantsHasExplicitZero: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8)]
enum ImplicitNonFirstVariantIsZero {
A = -1,
B,
}
util_assert_impl_all!(ImplicitNonFirstVariantIsZero: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u64)]
enum LargeDiscriminant {
A = 0xFFFF_FFFF_FFFF_FFFF,
B = 0x0000_0000_0000_0000,
}
util_assert_impl_all!(LargeDiscriminant: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum FirstVariantIsZeroable {
A(u32),
B { foo: u32 },
}
util_assert_impl_all!(FirstVariantIsZeroable: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum FirstVariantIsZeroableSecondIsNot {
A(bool),
B(::core::num::NonZeroU8),
}
util_assert_impl_all!(FirstVariantIsZeroableSecondIsNot: imp::FromZeros);
// MSRV does not support data-carrying enum variants with explicit discriminants
#[cfg(not(__ZEROCOPY_TOOLCHAIN = "msrv"))]
mod msrv_only {
use super::*;
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum ImplicitFirstVariantIsZeroable {
A(bool),
B(::core::num::NonZeroU8) = 1,
}
util_assert_impl_all!(ImplicitFirstVariantIsZeroable: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8)]
enum ImplicitNonFirstVariantIsZeroable {
A(::core::num::NonZeroU8) = 1,
B = -1,
C(bool),
}
util_assert_impl_all!(ImplicitNonFirstVariantIsZeroable: imp::FromZeros);
}

View File

@@ -0,0 +1,54 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Foo {
A,
}
util_assert_impl_all!(Foo: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Bar {
A = 0,
}
util_assert_impl_all!(Bar: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Baz {
A = 1,
B = 0,
}
util_assert_impl_all!(Baz: imp::KnownLayout);
// Deriving `KnownLayout` should work if the enum has bounded parameters.
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::KnownLayout,
{
Variant([T; N], imp::PhantomData<&'a &'b ()>),
}
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout);

View File

@@ -0,0 +1,55 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Foo {
A,
}
util_assert_impl_all!(Foo: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Bar {
A = 0,
}
util_assert_impl_all!(Bar: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Baz {
A = 1,
B = 0,
}
util_assert_impl_all!(Baz: imp::Immutable);
// Deriving `Immutable` should work if the enum has bounded parameters.
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::Immutable, const N: ::core::primitive::usize>
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::Immutable,
{
Variant([T; N], imp::PhantomData<&'a &'b ()>),
UnsafeCell(imp::PhantomData<imp::UnsafeCell<()>>, &'a imp::UnsafeCell<()>),
}
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::Immutable);

View File

@@ -0,0 +1,156 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// An enum is `IntoBytes` if if has a defined repr.
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum C {
A,
}
util_assert_impl_all!(C: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum U8 {
A,
}
util_assert_impl_all!(U8: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u16)]
enum U16 {
A,
}
util_assert_impl_all!(U16: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum U32 {
A,
}
util_assert_impl_all!(U32: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u64)]
enum U64 {
A,
}
util_assert_impl_all!(U64: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(usize)]
enum Usize {
A,
}
util_assert_impl_all!(Usize: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8)]
enum I8 {
A,
}
util_assert_impl_all!(I8: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i16)]
enum I16 {
A,
}
util_assert_impl_all!(I16: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i32)]
enum I32 {
A,
}
util_assert_impl_all!(I32: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i64)]
enum I64 {
A,
}
util_assert_impl_all!(I64: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(isize)]
enum Isize {
A,
}
util_assert_impl_all!(Isize: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum HasData {
A(u8),
B(i8),
}
util_assert_impl_all!(HasData: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum HasData32 {
A(u32),
B(i32),
C([u8; 4]),
D([u16; 2]),
}
util_assert_impl_all!(HasData: imp::IntoBytes);
// After #1752 landed but before #1758 was fixed, this failed to compile because
// the padding check treated the tag type as being `#[repr(u8, align(2))] struct
// Tag { A }`, which is two bytes long, rather than the correct `#[repr(u8)]
// struct Tag { A }`, which is one byte long.
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, align(2))]
enum BadTagWouldHavePadding {
A(u8, u16),
}
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, align(2))]
enum HasAlign {
A(u8),
}
util_assert_impl_all!(HasAlign: imp::IntoBytes);

View File

@@ -0,0 +1,675 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(Eq, PartialEq, Debug, imp::Immutable, imp::KnownLayout, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum Foo {
A,
}
util_assert_impl_all!(Foo: imp::TryFromBytes);
#[test]
fn test_foo() {
imp::assert_eq!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[0]), imp::Ok(Foo::A));
imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[1]).is_err());
imp::assert!(<Foo as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
}
#[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u16)]
enum Bar {
A = 0,
}
util_assert_impl_all!(Bar: imp::TryFromBytes);
#[test]
fn test_bar() {
imp::assert_eq!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]), imp::Ok(Bar::A));
imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0]).is_err());
imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 1]).is_err());
imp::assert!(<Bar as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0]).is_err());
}
#[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum Baz {
A = 1,
B = 0,
}
util_assert_impl_all!(Baz: imp::TryFromBytes);
#[test]
fn test_baz() {
imp::assert_eq!(
<Baz as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&1u32)),
imp::Ok(Baz::A)
);
imp::assert_eq!(
<Baz as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&0u32)),
imp::Ok(Baz::B)
);
imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0]).is_err());
imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0]).is_err());
imp::assert!(<Baz as imp::TryFromBytes>::try_read_from_bytes(&[0, 0, 0, 0, 0]).is_err());
}
// Test hygiene - make sure that `i8` being shadowed doesn't cause problems for
// the code emitted by the derive.
type i8 = bool;
const THREE: ::core::primitive::i8 = 3;
#[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8)]
enum Blah {
A = 1,
B = 0,
C = 1 + 2,
D = 3 + THREE,
}
util_assert_impl_all!(Blah: imp::TryFromBytes);
#[test]
fn test_blah() {
imp::assert_eq!(
<Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&1i8)),
imp::Ok(Blah::A)
);
imp::assert_eq!(
<Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&0i8)),
imp::Ok(Blah::B)
);
imp::assert_eq!(
<Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&3i8)),
imp::Ok(Blah::C)
);
imp::assert_eq!(
<Blah as imp::TryFromBytes>::try_read_from_bytes(imp::IntoBytes::as_bytes(&6i8)),
imp::Ok(Blah::D)
);
imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[]).is_err());
imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[4]).is_err());
imp::assert!(<Blah as imp::TryFromBytes>::try_read_from_bytes(&[0, 0]).is_err());
}
#[derive(
Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum FieldlessButNotUnitOnly {
A,
B(),
C {},
}
#[test]
fn test_fieldless_but_not_unit_only() {
const SIZE: usize = ::core::mem::size_of::<FieldlessButNotUnitOnly>();
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(FieldlessButNotUnitOnly::A);
imp::assert_eq!(
<FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(FieldlessButNotUnitOnly::A)
);
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(FieldlessButNotUnitOnly::B());
imp::assert_eq!(
<FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(FieldlessButNotUnitOnly::B())
);
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(FieldlessButNotUnitOnly::C {});
imp::assert_eq!(
<FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(FieldlessButNotUnitOnly::C {})
);
imp::assert!(<FieldlessButNotUnitOnly as imp::TryFromBytes>::try_read_from_bytes(
&[0xFF; SIZE][..]
)
.is_err());
}
#[derive(
Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum WeirdDiscriminants {
A = -7,
B,
C = 33,
}
#[test]
fn test_weird_discriminants() {
const SIZE: usize = ::core::mem::size_of::<WeirdDiscriminants>();
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(WeirdDiscriminants::A);
imp::assert_eq!(
<WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(WeirdDiscriminants::A)
);
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(WeirdDiscriminants::B);
imp::assert_eq!(
<WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(WeirdDiscriminants::B)
);
let disc: [u8; SIZE] = ::zerocopy_renamed::transmute!(WeirdDiscriminants::C);
imp::assert_eq!(
<WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&disc[..]),
imp::Ok(WeirdDiscriminants::C)
);
imp::assert!(
<WeirdDiscriminants as imp::TryFromBytes>::try_read_from_bytes(&[0xFF; SIZE][..]).is_err()
);
}
// Technically non-portable since this is only `IntoBytes` if the discriminant
// is an `i32` or `u32`, but we'll cross that bridge when we get to it...
#[derive(
Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum HasFields {
A(u32),
B { foo: ::core::num::NonZeroU32 },
}
#[test]
fn test_has_fields() {
const SIZE: usize = ::core::mem::size_of::<HasFields>();
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(HasFields::A(10));
imp::assert_eq!(
<HasFields as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFields::A(10)),
);
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(HasFields::B {
foo: ::core::num::NonZeroU32::new(123456).unwrap()
});
imp::assert_eq!(
<HasFields as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFields::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
);
}
#[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, align(16))]
enum HasFieldsAligned {
A(u32),
B { foo: ::core::num::NonZeroU32 },
}
util_assert_impl_all!(HasFieldsAligned: imp::TryFromBytes);
#[test]
fn test_has_fields_aligned() {
const SIZE: usize = ::core::mem::size_of::<HasFieldsAligned>();
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct BytesOfHasFieldsAligned {
has_fields: HasFields,
padding: [u8; 8],
}
let wrap = |has_fields| BytesOfHasFieldsAligned { has_fields, padding: [0; 8] };
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(wrap(HasFields::A(10)));
imp::assert_eq!(
<HasFieldsAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsAligned::A(10)),
);
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(wrap(HasFields::B {
foo: ::core::num::NonZeroU32::new(123456).unwrap()
}));
imp::assert_eq!(
<HasFieldsAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsAligned::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
);
}
#[derive(
Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes, imp::IntoBytes,
)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum HasFieldsPrimitive {
A(u32),
B { foo: ::core::num::NonZeroU32 },
}
#[test]
fn test_has_fields_primitive() {
const SIZE: usize = ::core::mem::size_of::<HasFieldsPrimitive>();
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(HasFieldsPrimitive::A(10));
imp::assert_eq!(
<HasFieldsPrimitive as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsPrimitive::A(10)),
);
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(HasFieldsPrimitive::B {
foo: ::core::num::NonZeroU32::new(123456).unwrap(),
});
imp::assert_eq!(
<HasFieldsPrimitive as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsPrimitive::B { foo: ::core::num::NonZeroU32::new(123456).unwrap() }),
);
}
#[derive(Eq, PartialEq, Debug, imp::KnownLayout, imp::Immutable, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32, align(16))]
enum HasFieldsPrimitiveAligned {
A(u32),
B { foo: ::core::num::NonZeroU32 },
}
util_assert_impl_all!(HasFieldsPrimitiveAligned: imp::TryFromBytes);
#[test]
fn test_has_fields_primitive_aligned() {
const SIZE: usize = ::core::mem::size_of::<HasFieldsPrimitiveAligned>();
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct BytesOfHasFieldsPrimitiveAligned {
has_fields: HasFieldsPrimitive,
padding: [u8; 8],
}
let wrap = |has_fields| BytesOfHasFieldsPrimitiveAligned { has_fields, padding: [0; 8] };
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(wrap(HasFieldsPrimitive::A(10)));
imp::assert_eq!(
<HasFieldsPrimitiveAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsPrimitiveAligned::A(10)),
);
let bytes: [u8; SIZE] = ::zerocopy_renamed::transmute!(wrap(HasFieldsPrimitive::B {
foo: ::core::num::NonZeroU32::new(123456).unwrap()
}));
imp::assert_eq!(
<HasFieldsPrimitiveAligned as imp::TryFromBytes>::try_read_from_bytes(&bytes[..]),
imp::Ok(HasFieldsPrimitiveAligned::B {
foo: ::core::num::NonZeroU32::new(123456).unwrap()
}),
);
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(align(4), u32)]
enum HasReprAlignFirst {
A,
B,
}
util_assert_impl_all!(HasReprAlignFirst: imp::TryFromBytes);
#[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum Complex {
UnitLike,
StructLike { a: u8, b: u16 },
TupleLike(bool, char),
}
util_assert_impl_all!(Complex: imp::TryFromBytes);
#[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum ComplexWithGenerics<X, Y> {
UnitLike,
StructLike { a: u8, b: X },
TupleLike(bool, Y),
}
util_assert_impl_all!(ComplexWithGenerics<u16, char>: imp::TryFromBytes);
#[derive(imp::KnownLayout, imp::TryFromBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum GenericWithLifetimes<'a, 'b, X: 'a, Y: 'b> {
Foo(::core::marker::PhantomData<&'a X>),
Bar(::core::marker::PhantomData<&'b Y>),
}
#[derive(Clone, Copy, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct A;
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum B {
A(A),
A2 { a: A },
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum FooU8 {
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,
Variant255,
}
#[test]
fn test_trivial_is_bit_valid() {
// Though we don't derive `FromBytes`, `FooU8` *could* soundly implement
// `FromBytes`. Therefore, `TryFromBytes` derive's `is_bit_valid` impl is
// trivial - it unconditionally returns `true`.
util_assert_not_impl_any!(FooU8: imp::FromBytes);
util::test_trivial_is_bit_valid::<FooU8>();
}
#[deny(non_camel_case_types)]
mod issue_2051 {
use super::*;
// Test that the `non_camel_case_types` lint isn't triggered by generated
// code.
// Prevents regressions of #2051.
#[repr(u32)]
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[allow(non_camel_case_types)]
pub enum Code {
I32_ADD,
I32_SUB,
I32_MUL,
}
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum RawIdentifierVariant {
r#type,
}
util_assert_impl_all!(RawIdentifierVariant: imp::TryFromBytes);

View File

@@ -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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// An enum is `Unaligned` if:
// - No `repr(align(N > 1))`
// - `repr(u8)` or `repr(i8)`
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum Foo {
A,
}
util_assert_impl_all!(Foo: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8)]
enum Bar {
A,
}
util_assert_impl_all!(Bar: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, align(1))]
enum Baz {
A,
}
util_assert_impl_all!(Baz: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8, align(1))]
enum Blah {
B,
}
util_assert_impl_all!(Blah: imp::Unaligned);

34
vendor/zerocopy-derive/tests/eq.rs vendored Normal file
View File

@@ -0,0 +1,34 @@
// Copyright 2024 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::Debug, imp::IntoBytes, imp::Immutable, imp::ByteEq)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct {
a: u64,
b: u32,
c: u32,
}
util_assert_impl_all!(Struct: imp::IntoBytes, imp::PartialEq, imp::Eq);
#[test]
fn test_eq() {
use imp::{assert_eq, assert_ne};
let a = Struct { a: 10, b: 15, c: 20 };
let b = Struct { a: 10, b: 15, c: 25 };
assert_eq!(a, a);
assert_ne!(a, b);
assert_ne!(b, a);
}

39
vendor/zerocopy-derive/tests/hash.rs vendored Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2024 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::IntoBytes, imp::Immutable, imp::ByteHash)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct {
a: u64,
b: u32,
c: u32,
}
util_assert_impl_all!(Struct: imp::IntoBytes, imp::hash::Hash);
#[test]
fn test_hash() {
use imp::{
hash::{Hash, Hasher},
DefaultHasher,
};
fn hash(val: impl Hash) -> u64 {
let mut hasher = DefaultHasher::new();
val.hash(&mut hasher);
hasher.finish()
}
hash(Struct { a: 10, b: 15, c: 20 });
hash(&[Struct { a: 10, b: 15, c: 20 }, Struct { a: 5, b: 4, c: 3 }]);
}

60
vendor/zerocopy-derive/tests/hygiene.rs vendored Normal file
View File

@@ -0,0 +1,60 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
extern crate zerocopy_renamed as _zerocopy;
#[derive(_zerocopy::KnownLayout, _zerocopy::FromBytes, _zerocopy::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct TypeParams<'a, T, I: imp::Iterator> {
a: T,
c: I::Item,
d: u8,
e: imp::PhantomData<&'a [::core::primitive::u8]>,
f: imp::PhantomData<&'static ::core::primitive::str>,
g: imp::PhantomData<imp::String>,
}
util_assert_impl_all!(
TypeParams<'static, (), imp::IntoIter<()>>:
_zerocopy::KnownLayout,
_zerocopy::FromZeros,
_zerocopy::FromBytes,
_zerocopy::Unaligned
);
// Regression test for #2177.
//
// This test ensures that `#[derive(KnownLayout)]` does not trigger the
// `private_bounds` lint when used on a public struct in a macro.
mod issue_2177 {
#![deny(private_bounds)]
// We need to access `_zerocopy` from the parent module.
use super::_zerocopy;
macro_rules! define {
($name:ident, $repr:ty) => {
#[derive(_zerocopy::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct $name($repr);
};
}
define!(Foo, u8);
}

149
vendor/zerocopy-derive/tests/include.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
// 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.
// ON THE PRELUDE: All of the tests in this directory (excepting UI tests)
// disable the prelude via `#![no_implicit_prelude]`. This ensures that all code
// emitted by our derives doesn't accidentally assume that the prelude is
// included, which helps ensure that items are referred to by absolute path,
// which in turn ensures that these items can't accidentally refer to names
// which have been shadowed. For example, the code `x == None` could behave
// incorrectly if, in the scope in which the derive is invoked, `None` has been
// shadowed by `CONST None: Option<usize> = Some(1)`.
//
// `mod imp` allows us to import items and refer to them in this module without
// introducing the risk that this hides bugs in which derive-emitted code uses
// names which are not fully-qualified. For such a bug to manifest, it would
// need to be of the form `imp::Foo`, which is unlikely to happen by accident.
mod imp {
// Since this file is included in every test file, and since not every test
// file uses every item here, we allow unused imports to avoid generating
// warnings.
#[allow(unused)]
pub use {
::core::{
self, assert_eq, assert_ne,
cell::UnsafeCell,
convert::TryFrom,
hash,
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
option::IntoIter,
prelude::v1::*,
primitive::*,
},
::std::{collections::hash_map::DefaultHasher, prelude::v1::*},
::zerocopy_renamed::*,
};
}
// These items go in their own module (rather than the top level) for the same
// reason that we use `mod imp` above. See its comment for more details.
pub mod util {
/// A type that doesn't implement any zerocopy traits.
pub struct NotZerocopy<T = ()>(pub T);
/// A `u16` with alignment 2.
///
/// Though `u16` has alignment 2 on some platforms, it's not guaranteed. By
/// contrast, `util::AU16` is guaranteed to have alignment 2.
#[derive(
super::imp::KnownLayout,
super::imp::Immutable,
super::imp::FromBytes,
super::imp::IntoBytes,
Copy,
Clone,
)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, align(2))]
pub struct AU16(pub u16);
// Since we can't import these by path (ie, `util::assert_impl_all!`), use a
// name prefix to ensure our derive-emitted code isn't accidentally relying
// on `assert_impl_all!` being in scope.
#[macro_export]
macro_rules! util_assert_impl_all {
($type:ty: $($trait:path),+ $(,)?) => {
const _: fn() = || {
use ::core::prelude::v1::*;
::static_assertions::assert_impl_all!($type: $($trait),+);
};
};
}
// Since we can't import these by path (ie, `util::assert_not_impl_any!`),
// use a name prefix to ensure our derive-emitted code isn't accidentally
// relying on `assert_not_impl_any!` being in scope.
#[macro_export]
macro_rules! util_assert_not_impl_any {
($x:ty: $($t:path),+ $(,)?) => {
const _: fn() = || {
use ::core::prelude::v1::*;
::static_assertions::assert_not_impl_any!($x: $($t),+);
};
};
}
#[macro_export]
macro_rules! test_trivial_is_bit_valid {
($x:ty => $name:ident) => {
#[test]
fn $name() {
util::test_trivial_is_bit_valid::<$x>();
}
};
}
// Under some circumstances, our `TryFromBytes` derive generates a trivial
// `is_bit_valid` impl that unconditionally returns `true`. This test
// attempts to validate that this is, indeed, the behavior of our
// `TryFromBytes` derive. It is not foolproof, but is likely to catch some
// mistakes.
//
// As of this writing, this happens when deriving `TryFromBytes` thanks to a
// top-level `#[derive(FromBytes)]`.
pub fn test_trivial_is_bit_valid<T: super::imp::TryFromBytes>() {
use super::imp::{MaybeUninit, Ptr, ReadOnly};
// This test works based on the insight that a trivial `is_bit_valid`
// impl should never load any bytes from memory. Thus, while it is
// technically a violation of `is_bit_valid`'s safety precondition to
// pass a pointer to uninitialized memory, the `is_bit_valid` impl we
// expect our derives to generate should never touch this memory, and
// thus should never exhibit UB. By contrast, if our derives are
// spuriously generating non-trivial `is_bit_valid` impls, this should
// cause UB which may be caught by Miri.
let mut buf = MaybeUninit::<T>::uninit();
let ptr = Ptr::from_mut(&mut buf);
// SAFETY: This is intentionally unsound; see the preceding comment.
let ptr = unsafe { ptr.assume_initialized() };
let mut ptr = ptr.transmute::<ReadOnly<MaybeUninit<T>>, _, _>();
let ptr = ptr.reborrow_shared();
let ptr = ptr.cast::<_, ::zerocopy_renamed::pointer::cast::CastSized, _>();
assert!(<T as super::imp::TryFromBytes>::is_bit_valid(ptr));
}
pub fn test_is_bit_valid<T: super::imp::TryFromBytes, V: super::imp::IntoBytes>(
val: V,
is_bit_valid: bool,
) {
use super::imp::{
pointer::{cast::CastSized, BecauseImmutable},
ReadOnly,
};
let ro = ReadOnly::new(val);
let candidate = ::zerocopy_renamed::Ptr::from_ref(&ro);
let candidate = candidate.recall_validity();
let candidate = candidate.cast::<ReadOnly<T>, CastSized, (_, BecauseImmutable)>();
super::imp::assert_eq!(T::is_bit_valid(candidate), is_bit_valid);
}
}

View File

@@ -0,0 +1,21 @@
// Copyright 2024 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
#![forbid(unexpected_cfgs)]
include!("include.rs");
// Make sure no unexpected `cfg`s are emitted by our derives (see #2117).
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct Test(pub [u8; 32]);

View File

@@ -0,0 +1,23 @@
// Copyright 2025 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_renamed::{IntoBytes, Unalign};
#[allow(unused)]
#[derive(IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Struct {
leading: Unalign<u32>,
trailing: [u8],
}
#[test]
fn test_issue_2835() {
// Compilation is enough to verify the fix
}

View File

@@ -0,0 +1,292 @@
// Copyright 2026 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.
#![no_implicit_prelude]
#![deny(non_ascii_idents)]
#![allow(dead_code)]
include!("include.rs");
// FIXME(#2880): Derive `FromBytes` in all types once we support non-ASCII
// idents.
#[derive(imp::KnownLayout, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct TestStruct {
a: u8,
}
#[derive(imp::KnownLayout, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
union TestUnion {
a: u8,
}
#[derive(imp::KnownLayout, imp::FromBytes, imp::IntoBytes, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum FooU8 {
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,
Variant255,
}

View File

@@ -0,0 +1,78 @@
// Copyright 2026 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.
#![no_implicit_prelude]
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
include!("include.rs");
// Original reproducer from #2915
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum MyEnum {
Type,
OtherWithData(u8),
}
// Tests for all other associated types which may be problematic in our codebase
// as of this commit.
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned, imp::Immutable, imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct StructCollision {
pub Type: u8,
pub LAYOUT: u8,
pub PointerMetadata: u8,
pub Tag: u8,
pub tag: u8,
pub variants: u8,
}
impl StructCollision {
pub const Type: () = ();
pub const LAYOUT: () = ();
pub const PointerMetadata: () = ();
}
#[derive(imp::FromZeros, imp::Immutable, imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub enum EnumCollision {
Type { x: u8 },
LAYOUT { x: u8 },
PointerMetadata { x: u8 },
Tag { x: u8 },
tag { x: u8 },
variants { x: u8 },
}
// Case where generic parameter has associated type colliding with internal usage
pub trait AmbiguousTrait {
type Type;
const LAYOUT: usize;
type PointerMetadata;
}
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned, imp::Immutable, imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct GenericCollision<T: AmbiguousTrait> {
pub field: u8,
pub typ: T::Type,
pub pointer_metadata: T::PointerMetadata,
pub _marker: imp::PhantomData<T>,
}
#[test]
fn test_compilation() {
// If the derives compile, we are good.
let _ = StructCollision { Type: 0, LAYOUT: 0, PointerMetadata: 0, Tag: 0, tag: 0, variants: 0 };
let _ = EnumCollision::Type { x: 0 };
}

169
vendor/zerocopy-derive/tests/on_error.rs vendored Normal file
View File

@@ -0,0 +1,169 @@
// Copyright 2026 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
#![cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, feature(trivial_bounds))]
include!("include.rs");
#[derive(imp::FromBytes)]
#[zerocopy(on_error = "fail")]
#[zerocopy(crate = "zerocopy_renamed")]
struct LoudValid;
util_assert_impl_all!(LoudValid: imp::FromBytes);
// `derive(Unaligned)` fails without a repr.
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
struct Foo {
a: u8,
}
util_assert_impl_all!(Foo: imp::FromBytes, imp::IntoBytes);
util_assert_not_impl_any!(Foo: imp::Unaligned);
// Invalid enum for FromZeros (must have discriminant 0).
#[derive(imp::FromZeros)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum BadFromZerosEnum {
A = 1,
B = 2,
}
util_assert_not_impl_any!(BadFromZerosEnum: imp::FromZeros);
// Invalid enum for FromBytes (must have 256 variants).
#[derive(imp::FromBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum BadFromBytesEnum {
A = 0,
}
util_assert_not_impl_any!(BadFromBytesEnum: imp::FromBytes);
// Invalid enum for IntoBytes (invalid repr).
#[derive(imp::IntoBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[cfg_attr(
any(
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "nightly",
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "stable"
),
repr(Rust)
)]
enum BadIntoBytesEnum {
A,
}
util_assert_not_impl_any!(BadIntoBytesEnum: imp::IntoBytes);
// Invalid enum for Unaligned (invalid repr).
#[derive(imp::Unaligned)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u16)]
enum BadUnalignedEnum {
A,
}
util_assert_not_impl_any!(BadUnalignedEnum: imp::Unaligned);
// Invalid enum for TryFromBytes (invalid repr).
#[derive(imp::TryFromBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[cfg_attr(
any(
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "nightly",
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "stable"
),
repr(Rust)
)]
enum BadTryFromBytesEnum {
A,
}
util_assert_not_impl_any!(BadTryFromBytesEnum: imp::TryFromBytes);
// Invalid union for IntoBytes (invalid repr).
#[derive(imp::IntoBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[cfg_attr(
any(
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "nightly",
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "stable"
),
repr(Rust)
)]
union BadIntoBytesUnion {
a: u8,
}
util_assert_not_impl_any!(BadIntoBytesUnion: imp::IntoBytes);
// Invalid union for Unaligned (invalid repr).
#[derive(imp::Unaligned)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[cfg_attr(
any(
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "nightly",
__ZEROCOPY_INTERNAL_USE_ONLY_TOOLCHAIN = "stable"
),
repr(Rust)
)]
union BadUnalignedUnion {
a: u8,
}
util_assert_not_impl_any!(BadUnalignedUnion: imp::Unaligned);
// Invalid union for IntoBytes (generic).
#[derive(imp::IntoBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
union BadIntoBytesUnionGeneric<T: imp::Copy> {
a: T,
}
util_assert_not_impl_any!(BadIntoBytesUnionGeneric<u8>: imp::IntoBytes);
#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
mod trivial_bounds {
use super::*;
#[derive(imp::FromBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct TrivialBounds(bool);
util_assert_not_impl_any!(TrivialBounds: imp::FromBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(on_error = "skip")]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct BadIntoBytesStructPadding {
a: u8,
b: u16,
}
util_assert_not_impl_any!(BadIntoBytesStructPadding: imp::IntoBytes);
}

View File

@@ -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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// Ensure that types that are use'd and types that are referenced by path work.
mod foo {
use super::*;
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct Foo {
foo: u8,
}
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct Bar {
bar: u8,
}
}
use foo::Foo;
#[derive(imp::FromBytes, imp::IntoBytes, imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Baz {
foo: Foo,
bar: foo::Bar,
}

View File

@@ -0,0 +1,36 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// FIXME(#847): Make this test succeed on earlier Rust versions.
#[::rustversion::stable(1.59)]
mod test {
use super::*;
// 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(imp::KnownLayout, imp::IntoBytes, imp::FromZeros, imp::FromBytes, imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
pub struct Public(Private);
#[derive(imp::KnownLayout, imp::IntoBytes, imp::FromZeros, imp::FromBytes, imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Private(());
}

View File

@@ -0,0 +1,83 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// A struct is `FromBytes` if:
// - all fields are `FromBytes`
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Zst;
util_assert_impl_all!(Zst: imp::FromBytes);
test_trivial_is_bit_valid!(Zst => test_zst_trivial_is_bit_valid);
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct One {
a: u8,
}
util_assert_impl_all!(One: imp::FromBytes);
test_trivial_is_bit_valid!(One => test_one_trivial_is_bit_valid);
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Two {
a: u8,
b: Zst,
}
util_assert_impl_all!(Two: imp::FromBytes);
test_trivial_is_bit_valid!(Two => test_two_trivial_is_bit_valid);
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Unsized {
a: [u8],
}
util_assert_impl_all!(Unsized: imp::FromBytes);
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [::core::primitive::u8]>,
d: imp::PhantomData<&'static ::core::primitive::str>,
e: imp::PhantomData<imp::String>,
f: T,
}
util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::FromBytes);
util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::FromBytes);
util_assert_impl_all!(TypeParams<'static, [util::AU16], imp::IntoIter<()>>: imp::FromBytes);
test_trivial_is_bit_valid!(TypeParams<'static, (), imp::IntoIter<()>> => test_type_params_trivial_is_bit_valid);
// Deriving `FromBytes` should work if the struct has bounded parameters.
#[derive(imp::FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::FromBytes, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::FromBytes;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::FromBytes);
test_trivial_is_bit_valid!(WithParams<'static, 'static, u8, 42> => test_with_params_trivial_is_bit_valid);

View File

@@ -0,0 +1,78 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// A struct is `FromZeros` if:
// - all fields are `FromZeros`
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Zst;
util_assert_impl_all!(Zst: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
struct One {
a: bool,
}
util_assert_impl_all!(One: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Two {
a: bool,
b: Zst,
}
util_assert_impl_all!(Two: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Unsized {
a: [u8],
}
util_assert_impl_all!(Unsized: imp::FromZeros);
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [u8]>,
d: imp::PhantomData<&'static str>,
e: imp::PhantomData<imp::String>,
f: T,
}
util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::FromZeros);
util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::FromZeros);
util_assert_impl_all!(TypeParams<'static, [util::AU16], imp::IntoIter<()>>: imp::FromZeros);
// Deriving `FromZeros` should work if the struct has bounded parameters.
#[derive(imp::FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::FromZeros, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::FromZeros;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::FromZeros);

View File

@@ -0,0 +1,131 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
extern crate rustversion;
include!("include.rs");
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Zst;
util_assert_impl_all!(Zst: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
struct One {
a: bool,
}
util_assert_impl_all!(One: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Two {
a: bool,
b: Zst,
}
util_assert_impl_all!(Two: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
struct TypeParams<'a, T, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [::core::primitive::u8]>,
d: imp::PhantomData<&'static ::core::primitive::str>,
e: imp::PhantomData<imp::String>,
f: T,
}
util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::KnownLayout);
util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::KnownLayout);
// Deriving `KnownLayout` should work if the struct has bounded parameters.
//
// N.B. We limit this test to rustc >= 1.62, since earlier versions of rustc ICE
// when `KnownLayout` is derived on a `repr(C)` struct whose trailing field
// contains non-static lifetimes.
#[rustversion::since(1.62)]
const _: () = {
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::KnownLayout;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout);
};
const _: () = {
// Similar to the previous test, except that the trailing field contains
// only static lifetimes. This is exercisable on all supported toolchains.
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>(
&'a &'b [T; N],
imp::PhantomData<&'static ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::KnownLayout;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout);
};
// Deriving `KnownLayout` should work if the struct references `Self`. See
// #2116.
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct WithSelfReference {
leading: [u8; Self::N],
trailing: [[u8; Self::N]],
}
impl WithSelfReference {
const N: usize = 42;
}
util_assert_impl_all!(WithSelfReference: imp::KnownLayout);
// Deriving `KnownLayout` should work with generic `repr(packed)` types. See
// #2302.
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
struct Packet<P> {
payload: P,
}
util_assert_impl_all!(Packet<imp::u8>: imp::KnownLayout);
#[derive(imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct RawIdentifier {
r#type: u8,
}
util_assert_impl_all!(RawIdentifier: imp::KnownLayout);

View File

@@ -0,0 +1,105 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Zst;
util_assert_impl_all!(Zst: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct One {
a: bool,
}
util_assert_impl_all!(One: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Two {
a: bool,
b: Zst,
}
util_assert_impl_all!(Two: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Three {
a: [u8],
}
util_assert_impl_all!(Three: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Four<'a> {
field: &'a imp::UnsafeCell<u8>,
}
util_assert_impl_all!(Four<'static>: imp::Immutable);
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct TypeParams<'a, T, U, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [::core::primitive::u8]>,
d: imp::PhantomData<&'static ::core::primitive::str>,
e: imp::PhantomData<imp::String>,
f: imp::PhantomData<U>,
g: T,
}
util_assert_impl_all!(TypeParams<'static, (), (), imp::IntoIter<()>>: imp::Immutable);
util_assert_impl_all!(TypeParams<'static, util::AU16, util::AU16, imp::IntoIter<()>>: imp::Immutable);
util_assert_impl_all!(TypeParams<'static, util::AU16, imp::UnsafeCell<u8>, imp::IntoIter<()>>: imp::Immutable);
util_assert_not_impl_any!(TypeParams<'static, imp::UnsafeCell<()>, (), imp::IntoIter<()>>: imp::Immutable);
util_assert_not_impl_any!(TypeParams<'static, [imp::UnsafeCell<u8>; 0], (), imp::IntoIter<()>>: imp::Immutable);
util_assert_not_impl_any!(TypeParams<'static, (), (), imp::IntoIter<imp::UnsafeCell<()>>>: imp::Immutable);
trait Trait {
type Assoc;
}
impl<T> Trait for imp::UnsafeCell<T> {
type Assoc = T;
}
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
struct WithAssocType<T: Trait> {
field: <T as Trait>::Assoc,
}
util_assert_impl_all!(WithAssocType<imp::UnsafeCell<u8>>: imp::Immutable);
// Deriving `Immutable` should work if the struct has bounded parameters.
#[derive(imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::Immutable, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
imp::PhantomData<imp::UnsafeCell<()>>,
&'a imp::UnsafeCell<()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::Immutable;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::Immutable);

View File

@@ -0,0 +1,229 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// A struct is `IntoBytes` if:
// - all fields are `IntoBytes`
// - `repr(C)` or `repr(transparent)` and
// - no padding (size of struct equals sum of size of field types)
// - `repr(packed)`
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct CZst;
util_assert_impl_all!(CZst: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct C {
a: u8,
b: u8,
c: util::AU16,
}
util_assert_impl_all!(C: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct SyntacticUnsized {
a: u8,
b: u8,
c: [util::AU16],
}
util_assert_impl_all!(C: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct Transparent {
a: u8,
b: (),
}
util_assert_impl_all!(Transparent: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct TransparentGeneric<T: ?imp::Sized> {
a: (),
b: T,
}
util_assert_impl_all!(TransparentGeneric<u64>: imp::IntoBytes);
util_assert_impl_all!(TransparentGeneric<[u64]>: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
struct CZstPacked;
util_assert_impl_all!(CZstPacked: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[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,
}
util_assert_impl_all!(CPacked: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[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,
}
util_assert_impl_all!(CPacked2: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
struct CPackedGeneric<T, U: ?imp::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: imp::ManuallyDrop<U>,
}
util_assert_impl_all!(CPackedGeneric<u8, util::AU16>: imp::IntoBytes);
util_assert_impl_all!(CPackedGeneric<u8, [util::AU16]>: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(packed)]
struct PackedGeneric<T, U: ?imp::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: imp::ManuallyDrop<U>,
}
util_assert_impl_all!(PackedGeneric<u8, util::AU16>: imp::IntoBytes);
util_assert_impl_all!(PackedGeneric<u8, [util::AU16]>: imp::IntoBytes);
// This test is non-portable, but works so long as Rust happens to lay this
// struct out with no padding.
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct Unpacked {
a: u8,
b: u8,
}
util_assert_impl_all!(Unpacked: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct ReprCGenericOneField<T: ?imp::Sized> {
t: T,
}
// Even though `ReprCGenericOneField` has generic type arguments, since it only
// has one field, we don't require that its field types implement `Unaligned`.
util_assert_impl_all!(ReprCGenericOneField<util::AU16>: imp::IntoBytes);
util_assert_impl_all!(ReprCGenericOneField<[util::AU16]>: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct ReprCGenericMultipleFields<T, U: ?imp::Sized> {
t: T,
u: U,
}
// Since `ReprCGenericMultipleFields` is generic and has more than one field,
// all field types must implement `Unaligned`.
util_assert_impl_all!(ReprCGenericMultipleFields<u8, [u8; 2]>: imp::IntoBytes);
util_assert_impl_all!(ReprCGenericMultipleFields<u8, [[u8; 2]]>: imp::IntoBytes);
util_assert_not_impl_any!(ReprCGenericMultipleFields<u8, util::AU16>: imp::IntoBytes);
util_assert_not_impl_any!(ReprCGenericMultipleFields<u8, [util::AU16]>: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct Unsized {
a: [u8],
}
util_assert_impl_all!(Unsized: imp::IntoBytes);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, align(2))]
struct UnsizedAligned {
a: [[u8; 2]],
}
util_assert_impl_all!(UnsizedAligned: imp::IntoBytes);
// Deriving `IntoBytes` should work if the struct has bounded parameters.
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::IntoBytes, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::IntoBytes;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::IntoBytes);
// Test for the failure reported in #1182.
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
pub struct IndexEntryFlags(u8);
#[derive(imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
pub struct IndexEntry<const SIZE_BLOCK_ID: usize> {
block_number: imp::native_endian::U64,
flags: IndexEntryFlags,
block_id: [u8; SIZE_BLOCK_ID],
}
util_assert_impl_all!(IndexEntry<0>: imp::IntoBytes);
util_assert_impl_all!(IndexEntry<1>: imp::IntoBytes);

View File

@@ -0,0 +1,223 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// A struct is `imp::TryFromBytes` if:
// - all fields are `imp::TryFromBytes`
#[test]
fn zst() {
crate::util::test_is_bit_valid::<(), _>((), true);
}
#[derive(imp::TryFromBytes, imp::Immutable, imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct One {
a: u8,
}
util_assert_impl_all!(One: imp::TryFromBytes);
#[test]
fn one() {
crate::util::test_is_bit_valid::<One, _>(One { a: 42 }, true);
crate::util::test_is_bit_valid::<One, _>(One { a: 43 }, true);
}
#[derive(imp::TryFromBytes, imp::Immutable, imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Two {
a: bool,
b: (),
}
util_assert_impl_all!(Two: imp::TryFromBytes);
#[test]
fn two() {
crate::util::test_is_bit_valid::<Two, _>(Two { a: false, b: () }, true);
crate::util::test_is_bit_valid::<Two, _>(Two { a: true, b: () }, true);
crate::util::test_is_bit_valid::<Two, _>([2u8], false);
}
#[derive(imp::KnownLayout, imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Unsized {
a: [u8],
}
util_assert_impl_all!(Unsized: imp::TryFromBytes);
#[test]
fn un_sized() {
// FIXME(#5): Use `try_transmute` in this test once it's available.
let mut buf = [16u8, 12, 42];
let candidate = ::zerocopy_renamed::Ptr::from_mut(&mut buf[..]);
// SAFETY: `&Unsized` consists entirely of initialized bytes.
let candidate = unsafe { candidate.assume_initialized() };
let mut candidate = {
use imp::pointer::{cast::CastUnsized, BecauseExclusive};
candidate.cast::<_, CastUnsized, (_, BecauseExclusive)>()
};
// SAFETY: `candidate`'s referent is as-initialized as `Two`.
let mut candidate = unsafe { candidate.assume_initialized() };
let is_bit_valid = <Unsized as imp::TryFromBytes>::is_bit_valid(candidate.reborrow_shared());
imp::assert!(is_bit_valid);
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [u8]>,
d: imp::PhantomData<&'static str>,
e: imp::PhantomData<imp::String>,
f: T,
}
util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::TryFromBytes);
util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::TryFromBytes);
util_assert_impl_all!(TypeParams<'static, [util::AU16], imp::IntoIter<()>>: imp::TryFromBytes);
// Deriving `imp::TryFromBytes` should work if the struct has bounded
// parameters.
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::TryFromBytes, const N: usize>(
imp::PhantomData<&'a &'b ()>,
[T],
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::TryFromBytes;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::TryFromBytes);
#[derive(imp::FromBytes, imp::IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct MaybeFromBytes<T>(T);
#[test]
fn test_maybe_from_bytes() {
// When deriving `FromBytes` on a type with no generic parameters, we emit a
// trivial `is_bit_valid` impl that always returns true. This test confirms
// that we *don't* spuriously do that when generic parameters are present.
crate::util::test_is_bit_valid::<MaybeFromBytes<bool>, _>(MaybeFromBytes(false), true);
crate::util::test_is_bit_valid::<MaybeFromBytes<bool>, _>(MaybeFromBytes(true), true);
crate::util::test_is_bit_valid::<MaybeFromBytes<bool>, _>([2u8], false);
}
#[derive(Debug, PartialEq, Eq, imp::TryFromBytes, imp::Immutable, imp::KnownLayout)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
struct CPacked {
a: u8,
// NOTE: The `u32` type is not guaranteed to have alignment 4, although it
// does on many platforms. However, to fix this would require a custom type
// with a `#[repr(align(4))]` attribute, and `#[repr(packed)]` types are not
// allowed to transitively contain `#[repr(align(...))]` types. Thus, we
// have no choice but to use `u32` here. Luckily, these tests run in CI on
// platforms on which `u32` has alignment 4, so this isn't that big of a
// deal.
b: u32,
}
#[test]
fn c_packed() {
let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF];
let converted = <CPacked as imp::TryFromBytes>::try_ref_from_bytes(candidate);
imp::assert_eq!(converted, imp::Ok(&CPacked { a: 42, b: u32::MAX }));
}
#[derive(imp::TryFromBytes, imp::KnownLayout, imp::Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, packed)]
struct CPackedUnsized {
a: u8,
// NOTE: The `u32` type is not guaranteed to have alignment 4, although it
// does on many platforms. However, to fix this would require a custom type
// with a `#[repr(align(4))]` attribute, and `#[repr(packed)]` types are not
// allowed to transitively contain `#[repr(align(...))]` types. Thus, we
// have no choice but to use `u32` here. Luckily, these tests run in CI on
// platforms on which `u32` has alignment 4, so this isn't that big of a
// deal.
b: [u32],
}
#[test]
fn c_packed_unsized() {
let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF];
let converted = <CPackedUnsized as imp::TryFromBytes>::try_ref_from_bytes(candidate);
imp::assert!(converted.is_ok());
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(packed)]
struct PackedUnsized {
a: u8,
// NOTE: The `u32` type is not guaranteed to have alignment 4, although it
// does on many platforms. However, to fix this would require a custom type
// with a `#[repr(align(4))]` attribute, and `#[repr(packed)]` types are not
// allowed to transitively contain `#[repr(align(...))]` types. Thus, we
// have no choice but to use `u32` here. Luckily, these tests run in CI on
// platforms on which `u32` has alignment 4, so this isn't that big of a
// deal.
b: [u32],
}
#[test]
fn packed_unsized() {
let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF];
let converted = <CPackedUnsized as imp::TryFromBytes>::try_ref_from_bytes(candidate);
imp::assert!(converted.is_ok());
let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let converted = <CPackedUnsized as imp::TryFromBytes>::try_ref_from_bytes(candidate);
imp::assert!(converted.is_err());
let candidate = &[42u8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let converted = <CPackedUnsized as imp::TryFromBytes>::try_ref_from_bytes(candidate);
imp::assert!(converted.is_ok());
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct A;
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
struct B {
a: A,
}
#[derive(imp::TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct RawIdent {
r#type: u8,
}
util_assert_impl_all!(RawIdent: imp::TryFromBytes);

View File

@@ -0,0 +1,103 @@
// 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.
// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]
include!("include.rs");
// 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(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct Foo {
a: u8,
}
util_assert_impl_all!(Foo: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct Bar {
a: u8,
}
util_assert_impl_all!(Bar: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[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,
}
util_assert_impl_all!(Baz: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, align(1))]
struct FooAlign {
a: u8,
}
util_assert_impl_all!(FooAlign: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct Unsized {
a: [u8],
}
util_assert_impl_all!(Unsized: imp::Unaligned);
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct TypeParams<'a, T: ?imp::Sized, I: imp::Iterator> {
a: I::Item,
b: u8,
c: imp::PhantomData<&'a [::core::primitive::u8]>,
d: imp::PhantomData<&'static ::core::primitive::str>,
e: imp::PhantomData<imp::String>,
f: T,
}
util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::Unaligned);
util_assert_impl_all!(TypeParams<'static, ::core::primitive::u8, imp::IntoIter<()>>: imp::Unaligned);
util_assert_impl_all!(TypeParams<'static, [::core::primitive::u8], imp::IntoIter<()>>: imp::Unaligned);
// Deriving `Unaligned` should work if the struct has bounded parameters.
#[derive(imp::Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
struct WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::Unaligned, const N: usize>(
[T; N],
imp::PhantomData<&'a &'b ()>,
)
where
'a: 'b,
'b: 'a,
T: 'a + 'b + imp::Unaligned;
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::Unaligned);

27
vendor/zerocopy-derive/tests/ui.rs vendored Normal file
View File

@@ -0,0 +1,27 @@
// 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::UiTestRunner;
#[test]
#[cfg_attr(miri, ignore)]
fn ui() {
// This tests the behavior when `--cfg zerocopy_derive_union_into_bytes` is
// present.
UiTestRunner::new()
.rustc_arg("--cfg=zerocopy_derive_union_into_bytes")
.rustc_arg("--cfg=zerocopy_unstable_derive_on_error")
.rustc_arg("-Wwarnings") // To ensure .stderr files reflect typical user encounter
.run();
// This tests the behavior when various `--cfg` flags are not present.
UiTestRunner::new()
.subdir("cfgs")
.rustc_arg("-Wwarnings") // To ensure .stderr files reflect typical user encounter
.run();
}

View File

@@ -0,0 +1,14 @@
error: use of deprecated struct `OldHeader`: Do not use
--> $DIR/absence_of_deprecated_warning.rs:32:12
|
32 | impl T for OldHeader {}
| ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/absence_of_deprecated_warning.rs:14:9
|
14 | #![deny(deprecated)]
| ^^^^^^^^^^
error: aborting due to previous error

View File

@@ -0,0 +1,28 @@
error: use of deprecated struct `OldHeader`: Do not use
--> $DIR/absence_of_deprecated_warning.rs:32:12
|
32 | impl T for OldHeader {}
| ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/absence_of_deprecated_warning.rs:14:9
|
14 | #![deny(deprecated)]
| ^^^^^^^^^^
warning: struct `OldHeader` is never constructed
--> $DIR/absence_of_deprecated_warning.rs:24:8
|
24 | struct OldHeader {
| ^^^^^^^^^
|
= note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
warning: trait `T` is never used
--> $DIR/absence_of_deprecated_warning.rs:29:7
|
29 | trait T {}
| ^
error: aborting due to 1 previous error; 2 warnings emitted

View File

@@ -0,0 +1,35 @@
// Copyright 2024 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.
//! See: https://github.com/google/zerocopy/issues/553
//! zerocopy must still allow derives of deprecated types.
//! This test has a hand-written impl of a deprecated type, and should result in a compilation
//! error. If zerocopy does not tack an allow(deprecated) annotation onto its impls, then this
//! test will fail because more than one compile error will be generated.
#![deny(deprecated)]
extern crate zerocopy_renamed;
use zerocopy_renamed::IntoBytes;
#[deprecated = "Do not use"]
#[derive(IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
struct OldHeader {
field_a: usize,
collection: [u8; 8],
}
trait T {}
// Intentionally trigger a deprecation error
impl T for OldHeader {}
//~[msrv, stable, nightly]^ ERROR: use of deprecated struct `OldHeader`: Do not use
fn main() {}

View File

@@ -0,0 +1,28 @@
error: use of deprecated struct `OldHeader`: Do not use
--> $DIR/absence_of_deprecated_warning.rs:32:12
|
32 | impl T for OldHeader {}
| ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/absence_of_deprecated_warning.rs:14:9
|
14 | #![deny(deprecated)]
| ^^^^^^^^^^
warning: struct `OldHeader` is never constructed
--> $DIR/absence_of_deprecated_warning.rs:24:8
|
24 | struct OldHeader {
| ^^^^^^^^^
|
= note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
warning: trait `T` is never used
--> $DIR/absence_of_deprecated_warning.rs:29:7
|
29 | trait T {}
| ^
error: aborting due to 1 previous error; 2 warnings emitted

View File

@@ -0,0 +1,20 @@
error: `on_error` is experimental; pass '--cfg zerocopy_unstable_derive_on_error' to enable
--> $DIR/on_error.rs:13:10
|
13 | #[derive(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 `bool: FromBytes` is not satisfied
--> $DIR/on_error.rs:13:10
|
13 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= 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: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,35 @@
error: `on_error` is experimental; pass '--cfg zerocopy_unstable_derive_on_error' to enable
--> $DIR/on_error.rs:13:10
|
13 | #[derive(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 `bool: FromBytes` is not satisfied
--> $DIR/on_error.rs:13:10
|
13 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= note: Consider adding `#[derive(FromBytes)]` to `bool`
= help: the following other types implement trait `FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 79 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: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,21 @@
// Copyright 2026 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_renamed;
use zerocopy_renamed::FromBytes;
#[derive(FromBytes)]
//~^ ERROR: `on_error` is experimental; pass '--cfg zerocopy_unstable_derive_on_error' to enable
//~| ERROR: the trait bound `bool: FromBytes` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
#[zerocopy(on_error = "skip")]
#[repr(C)]
struct Foo(bool);
fn main() {}

View File

@@ -0,0 +1,31 @@
error: `on_error` is experimental; pass '--cfg zerocopy_unstable_derive_on_error' to enable
--> $DIR/on_error.rs:13:10
|
13 | #[derive(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 `bool: FromBytes` is not satisfied
--> $DIR/on_error.rs:13:10
|
13 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= note: Consider adding `#[derive(FromBytes)]` to `bool`
= help: the following other types implement trait `FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 79 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: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,11 @@
error: requires --cfg zerocopy_derive_union_into_bytes;
please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802
--> $DIR/union_into_bytes_cfg.rs:20:10
|
20 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error

View File

@@ -0,0 +1,11 @@
error: requires --cfg zerocopy_derive_union_into_bytes;
please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802
--> $DIR/union_into_bytes_cfg.rs:20:10
|
20 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error

View File

@@ -0,0 +1,28 @@
// Copyright 2024 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.
//! See: https://github.com/google/zerocopy/issues/553
//! zerocopy must still allow derives of deprecated types.
//! This test has a hand-written impl of a deprecated type, and should result in a compilation
//! error. If zerocopy does not tack an allow(deprecated) annotation onto its impls, then this
//! test will fail because more than one compile error will be generated.
#![deny(deprecated)]
extern crate zerocopy_renamed;
use zerocopy_renamed::IntoBytes;
#[derive(IntoBytes)]
//~^ ERROR: requires --cfg zerocopy_derive_union_into_bytes
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
union Foo {
a: u8,
}
fn main() {}

View File

@@ -0,0 +1,11 @@
error: requires --cfg zerocopy_derive_union_into_bytes;
please let us know you use this feature: https://github.com/google/zerocopy/discussions/1802
--> $DIR/union_into_bytes_cfg.rs:20:10
|
20 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error

View File

@@ -0,0 +1,93 @@
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::TryFromBytes` is not satisfied
--> $DIR/derive_transparent.rs:35:1
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy_renamed::TryFromBytes` is not implemented for `NotZerocopy`
|
note: required because of the requirements on the impl of `zerocopy_renamed::TryFromBytes` for `TransparentStruct<NotZerocopy>`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:35:1
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
= note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied
--> $DIR/derive_transparent.rs:38:1
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromZeros` is not implemented for `NotZerocopy`
|
note: required because of the requirements on the impl of `FromZeros` for `TransparentStruct<NotZerocopy>`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:38:1
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
= note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::FromBytes` is not satisfied
--> $DIR/derive_transparent.rs:41:1
|
41 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy_renamed::FromBytes` is not implemented for `NotZerocopy`
|
note: required because of the requirements on the impl of `zerocopy_renamed::FromBytes` for `TransparentStruct<NotZerocopy>`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:41:1
|
41 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
= note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::IntoBytes` is not satisfied
--> $DIR/derive_transparent.rs:44:1
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy_renamed::IntoBytes` is not implemented for `NotZerocopy`
|
note: required because of the requirements on the impl of `zerocopy_renamed::IntoBytes` for `TransparentStruct<NotZerocopy>`
--> $DIR/derive_transparent.rs:24:10
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:44:1
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
= note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::Unaligned` is not satisfied
--> $DIR/derive_transparent.rs:47:1
|
47 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy_renamed::Unaligned` is not implemented for `NotZerocopy`
|
note: required because of the requirements on the impl of `zerocopy_renamed::Unaligned` for `TransparentStruct<NotZerocopy>`
--> $DIR/derive_transparent.rs:24:32
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:47:1
|
47 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
= note: this error originates in the macro `::static_assertions::assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,198 @@
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::TryFromBytes` is not satisfied
--> $DIR/derive_transparent.rs:35:23
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::TryFromBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::TryFromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 154 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::TryFromBytes`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/../include.rs:74:17
|
74 | ::static_assertions::assert_impl_all!($type: $($trait),+);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
|
::: $DIR/derive_transparent.rs:35:1
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ------------------------------------------------------------------- in this macro invocation
= note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied
--> $DIR/derive_transparent.rs:38:23
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `FromZeros` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy`
= help: the following other types implement trait `FromZeros`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 142 others
note: required for `TransparentStruct<NotZerocopy>` to implement `FromZeros`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/../include.rs:74:17
|
74 | ::static_assertions::assert_impl_all!($type: $($trait),+);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
|
::: $DIR/derive_transparent.rs:38:1
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ---------------------------------------------------------------- in this macro invocation
= note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::FromBytes` is not satisfied
--> $DIR/derive_transparent.rs:41:23
|
41 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::FromBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 80 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::FromBytes`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/../include.rs:74:17
|
74 | ::static_assertions::assert_impl_all!($type: $($trait),+);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
|
::: $DIR/derive_transparent.rs:41:1
|
41 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
| ---------------------------------------------------------------- in this macro invocation
= note: this error originates in the derive macro `FromBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::IntoBytes` is not satisfied
--> $DIR/derive_transparent.rs:44:23
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::IntoBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::IntoBytes`:
()
AU16
AtomicBool
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
and 69 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::IntoBytes`
--> $DIR/derive_transparent.rs:24:10
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/../include.rs:74:17
|
74 | ::static_assertions::assert_impl_all!($type: $($trait),+);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
|
::: $DIR/derive_transparent.rs:44:1
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ---------------------------------------------------------------- in this macro invocation
= note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::Unaligned` is not satisfied
--> $DIR/derive_transparent.rs:47:23
|
47 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::Unaligned` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::Unaligned`:
()
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
and 27 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::Unaligned`
--> $DIR/derive_transparent.rs:24:32
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/../include.rs:74:17
|
74 | ::static_assertions::assert_impl_all!($type: $($trait),+);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
|
::: $DIR/derive_transparent.rs:47:1
|
47 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
| ---------------------------------------------------------------- in this macro invocation
= note: this error originates in the derive macro `Unaligned` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,48 @@
// 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_renamed;
#[path = "../include.rs"]
mod util;
use core::marker::PhantomData;
use zerocopy_renamed::{FromBytes, FromZeros, IntoBytes, TryFromBytes, Unaligned};
use self::util::util::NotZerocopy;
fn main() {}
// Test generic transparent structs
#[derive(IntoBytes, FromBytes, Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[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.
util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotZerocopy: zerocopy_renamed::TryFromBytes` is not satisfied
util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotZerocopy: FromZeros` is not satisfied
util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotZerocopy: zerocopy_renamed::FromBytes` is not satisfied
util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotZerocopy: zerocopy_renamed::IntoBytes` is not satisfied
util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotZerocopy: zerocopy_renamed::Unaligned` is not satisfied

View File

@@ -0,0 +1,173 @@
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::TryFromBytes` is not satisfied
--> $DIR/derive_transparent.rs:35:23
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::TryFromBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(TryFromBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::TryFromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 154 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::TryFromBytes`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:35:1
|
35 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: TryFromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: FromZeros` is not satisfied
--> $DIR/derive_transparent.rs:38:23
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `FromZeros` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(FromZeros)]` to `NotZerocopy`
= help: the following other types implement trait `FromZeros`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 142 others
note: required for `TransparentStruct<NotZerocopy>` to implement `FromZeros`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:38:1
|
38 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromZeros);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::FromBytes` is not satisfied
--> $DIR/derive_transparent.rs:41:23
|
41 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: FromBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::FromBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(FromBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 80 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::FromBytes`
--> $DIR/derive_transparent.rs:24:21
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:41:1
|
41 | util_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 `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::IntoBytes` is not satisfied
--> $DIR/derive_transparent.rs:44:23
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::IntoBytes` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(IntoBytes)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::IntoBytes`:
()
AU16
AtomicBool
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
and 69 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::IntoBytes`
--> $DIR/derive_transparent.rs:24:10
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:44:1
|
44 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: IntoBytes);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_impl_all`
= note: this error originates in the derive macro `IntoBytes` which comes from the expansion of the macro `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotZerocopy: zerocopy_renamed::Unaligned` is not satisfied
--> $DIR/derive_transparent.rs:47:23
|
47 | util_assert_impl_all!(TransparentStruct<NotZerocopy>: Unaligned);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `zerocopy_renamed::Unaligned` is not implemented for `NotZerocopy`
--> $DIR/../include.rs:48:5
|
48 | pub struct NotZerocopy<T = ()>(pub T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(Unaligned)]` to `NotZerocopy`
= help: the following other types implement trait `zerocopy_renamed::Unaligned`:
()
AtomicBool
AtomicI8
AtomicU8
Cell<T>
F32<O>
F64<O>
I128<O>
and 27 others
note: required for `TransparentStruct<NotZerocopy>` to implement `zerocopy_renamed::Unaligned`
--> $DIR/derive_transparent.rs:24:32
|
24 | #[derive(IntoBytes, FromBytes, Unaligned)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `_::{closure#0}::_::{closure#0}::assert_impl_all`
--> $DIR/derive_transparent.rs:47:1
|
47 | util_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 `util_assert_impl_all` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,419 @@
error: unrecognized representation hint
--> $DIR/enum.rs:20:8
|
20 | #[repr("foo")]
| ^^^^^
error: unrecognized representation hint
--> $DIR/enum.rs:29:8
|
29 | #[repr(foo)]
| ^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:36:10
|
36 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this conflicts with another representation hint
--> $DIR/enum.rs:46:12
|
46 | #[repr(u8, u16)]
| ^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:53:10
|
53 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:88:1
|
88 | #[zerocopy(crate = "zerocopy_renamed")]
| ^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:95:1
|
95 | #[zerocopy(crate = "zerocopy_renamed")]
| ^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:117:1
|
117 | #[zerocopy(crate = "zerocopy_renamed")]
| ^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:124:1
|
124 | #[zerocopy(crate = "zerocopy_renamed")]
| ^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:132:1
|
132 | #[zerocopy(crate = "zerocopy_renamed")]
| ^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
--> $DIR/enum.rs:140:1
|
140 | / #[zerocopy(crate = "zerocopy_renamed")]
141 | |
142 | | #[repr(u8)]
143 | | enum FromZeros4 {
144 | | A = 1,
145 | | B = 2,
146 | | }
| |_^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero.
--> $DIR/enum.rs:151:1
|
151 | / #[zerocopy(crate = "zerocopy_renamed")]
152 | |
153 | | #[repr(i8)]
154 | | enum FromZeros5 {
155 | | A = NEGATIVE_ONE,
156 | | B,
157 | | }
| |_^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
--> $DIR/enum.rs:171:1
|
171 | / #[zerocopy(crate = "zerocopy_renamed")]
172 | |
173 | | #[repr(u8)]
174 | | enum FromZeros7 {
... |
177 | | B(NotFromZeros),
178 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:184:10
|
184 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:193:8
|
193 | #[repr(C)]
| ^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:201:8
|
201 | #[repr(usize)]
| ^^^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:209:8
|
209 | #[repr(isize)]
| ^^^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:217:8
|
217 | #[repr(u32)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:225:8
|
225 | #[repr(i32)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:233:8
|
233 | #[repr(u64)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:241:8
|
241 | #[repr(i64)]
| ^^^
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:515:10
|
515 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:523:10
|
523 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:531:10
|
531 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:539:10
|
539 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:547:10
|
547 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:555:10
|
555 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:563:10
|
563 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:571:10
|
571 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:579:10
|
579 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot derive `Unaligned` on type with alignment greater than 1
--> $DIR/enum.rs:589:12
|
589 | #[repr(u8, align(2))]
| ^^^^^
error: cannot derive `Unaligned` on type with alignment greater than 1
--> $DIR/enum.rs:597:12
|
597 | #[repr(i8, align(2))]
| ^^^^^
error: this conflicts with another representation hint
--> $DIR/enum.rs:605:18
|
605 | #[repr(align(1), align(2))]
| ^^^^^
error: this conflicts with another representation hint
--> $DIR/enum.rs:613:18
|
613 | #[repr(align(2), align(4))]
| ^^^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:657:10
|
657 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:665:10
|
665 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: generic parameters may not be used in const operations
--> $DIR/enum.rs:677:7
|
677 | A(T),
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
error[E0658]: custom discriminant values are not allowed in enums with tuple or struct variants
--> $DIR/enum.rs:175:9
|
175 | A = 1,
| ^ disallowed custom discriminant
176 |
177 | B(NotFromZeros),
| --------------- tuple variant defined here
|
= note: see issue #60553 <https://github.com/rust-lang/rust/issues/60553> for more information
error[E0565]: meta item in `repr` must be an identifier
--> $DIR/enum.rs:20:8
|
20 | #[repr("foo")]
| ^^^^^
error[E0552]: unrecognized representation hint
--> $DIR/enum.rs:29:8
|
29 | #[repr(foo)]
| ^^^
error[E0566]: conflicting representation hints
--> $DIR/enum.rs:46:8
|
46 | #[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>
error[E0277]: the trait bound `UnsafeCell<()>: Immutable` is not satisfied
--> $DIR/enum.rs:64:10
|
64 | #[derive(Immutable)]
| ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<()>`
|
= help: see issue #48214
= note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `UnsafeCell<u8>: Immutable` is not satisfied
--> $DIR/enum.rs:75:10
|
75 | #[derive(Immutable)]
| ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<u8>`
|
= help: see issue #48214
= note: this error originates in the derive macro `Immutable` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotTryFromBytes: TryFromBytes` is not satisfied
--> $DIR/enum.rs:104:10
|
104 | #[derive(TryFromBytes)]
| ^^^^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotTryFromBytes`
|
= help: see issue #48214
= note: this error originates in the derive macro `TryFromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotFromZeros: TryFromBytes` is not satisfied
--> $DIR/enum.rs:161:10
|
161 | #[derive(FromZeros)]
| ^^^^^^^^^ the trait `TryFromBytes` is not implemented for `NotFromZeros`
|
= help: see issue #48214
= note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `NotFromZeros: FromZeros` is not satisfied
--> $DIR/enum.rs:161:10
|
161 | #[derive(FromZeros)]
| ^^^^^^^^^ the trait `FromZeros` is not implemented for `NotFromZeros`
|
= help: see issue #48214
= note: this error originates in the derive macro `FromZeros` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `bool: FromBytes` is not satisfied
--> $DIR/enum.rs:247:10
|
247 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= 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 `(): PaddingFree<IntoBytes1, 1_usize>` is not satisfied
--> $DIR/enum.rs:623:10
|
623 | #[derive(IntoBytes)]
| ^^^^^^^^^ the trait `PaddingFree<IntoBytes1, 1_usize>` is not implemented for `()`
|
= help: the following implementations were found:
<() as PaddingFree<T, 0_usize>>
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `(): PaddingFree<IntoBytes2, 3_usize>` is not satisfied
--> $DIR/enum.rs:638:10
|
638 | #[derive(IntoBytes)]
| ^^^^^^^^^ the trait `PaddingFree<IntoBytes2, 3_usize>` is not implemented for `()`
|
= help: the following implementations were found:
<() as PaddingFree<T, 0_usize>>
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `(): PaddingFree<IntoBytes3, 2_usize>` is not satisfied
--> $DIR/enum.rs:647:10
|
647 | #[derive(IntoBytes)]
| ^^^^^^^^^ the trait `PaddingFree<IntoBytes3, 2_usize>` is not implemented for `()`
|
= help: the following implementations were found:
<() as PaddingFree<T, 0_usize>>
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/enum.rs:672:10
|
672 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
note: not a concrete type
--> $DIR/enum.rs:672:10
|
672 | #[derive(IntoBytes)]
| ^^^^^^^^^
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `(): PaddingFree<IntoBytes7, 1_usize>` is not satisfied
--> $DIR/enum.rs:681:10
|
681 | #[derive(IntoBytes)]
| ^^^^^^^^^ the trait `PaddingFree<IntoBytes7, 1_usize>` is not implemented for `()`
|
= help: the following implementations were found:
<() as PaddingFree<T, 0_usize>>
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 52 previous errors
Some errors have detailed explanations: E0277, E0552, E0565, E0566, E0658.
For more information about an error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,601 @@
error: unrecognized representation hint
--> $DIR/enum.rs:20:8
|
20 | #[repr("foo")]
| ^^^^^
error: unrecognized representation hint
--> $DIR/enum.rs:29:8
|
29 | #[repr(foo)]
| ^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:36:10
|
36 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this conflicts with another representation hint
--> $DIR/enum.rs:46:8
|
46 | #[repr(u8, u16)]
| ^^^^^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:53:10
|
53 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:88:1
|
88 | / #[zerocopy(crate = "zerocopy_renamed")]
89 | |
90 | | enum TryFromBytes1 {
91 | | A,
92 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:95:1
|
95 | / #[zerocopy(crate = "zerocopy_renamed")]
96 | |
97 | | enum TryFromBytes2 {
98 | | A,
99 | | B(u8),
100 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:117:1
|
117 | / #[zerocopy(crate = "zerocopy_renamed")]
118 | |
119 | | enum FromZeros1 {
120 | | A(u8),
121 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:124:1
|
124 | / #[zerocopy(crate = "zerocopy_renamed")]
125 | |
126 | | enum FromZeros2 {
127 | | A,
128 | | B(u8),
129 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:132:1
|
132 | / #[zerocopy(crate = "zerocopy_renamed")]
133 | |
134 | | enum FromZeros3 {
135 | | A = 1,
136 | | B,
137 | | }
| |_^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
--> $DIR/enum.rs:140:1
|
140 | / #[zerocopy(crate = "zerocopy_renamed")]
141 | |
142 | | #[repr(u8)]
143 | | enum FromZeros4 {
144 | | A = 1,
145 | | B = 2,
146 | | }
| |_^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
help: This enum has discriminants which are not literal integers. One of those may define or imply which variant has a discriminant of zero. Use a literal integer to define or imply the variant with a discriminant of zero.
--> $DIR/enum.rs:151:1
|
151 | / #[zerocopy(crate = "zerocopy_renamed")]
152 | |
153 | | #[repr(i8)]
154 | | enum FromZeros5 {
155 | | A = NEGATIVE_ONE,
156 | | B,
157 | | }
| |_^
error: FromZeros only supported on enums with a variant that has a discriminant of `0`
--> $DIR/enum.rs:171:1
|
171 | / #[zerocopy(crate = "zerocopy_renamed")]
172 | |
173 | | #[repr(u8)]
174 | | enum FromZeros7 {
... |
177 | | B(NotFromZeros),
178 | | }
| |_^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:184:10
|
184 | #[derive(FromBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:193:8
|
193 | #[repr(C)]
| ^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:201:8
|
201 | #[repr(usize)]
| ^^^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:209:8
|
209 | #[repr(isize)]
| ^^^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:217:8
|
217 | #[repr(u32)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:225:8
|
225 | #[repr(i32)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:233:8
|
233 | #[repr(u64)]
| ^^^
error: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
--> $DIR/enum.rs:241:8
|
241 | #[repr(i64)]
| ^^^
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:515:10
|
515 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:523:10
|
523 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:531:10
|
531 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:539:10
|
539 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:547:10
|
547 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:555:10
|
555 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:563:10
|
563 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:571:10
|
571 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
--> $DIR/enum.rs:579:10
|
579 | #[derive(Unaligned)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot derive `Unaligned` on type with alignment greater than 1
--> $DIR/enum.rs:589:12
|
589 | #[repr(u8, align(2))]
| ^^^^^^^^
error: cannot derive `Unaligned` on type with alignment greater than 1
--> $DIR/enum.rs:597:12
|
597 | #[repr(i8, align(2))]
| ^^^^^^^^
error: this conflicts with another representation hint
--> $DIR/enum.rs:605:8
|
605 | #[repr(align(1), align(2))]
| ^^^^^^^^^^^^^^^^^^
error: this conflicts with another representation hint
--> $DIR/enum.rs:613:8
|
613 | #[repr(align(2), align(4))]
| ^^^^^^^^^^^^^^^^^^
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:657:10
|
657 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
--> $DIR/enum.rs:665:10
|
665 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: generic parameters may not be used in const operations
--> $DIR/enum.rs:677:7
|
677 | A(T),
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error[E0565]: meta item in `repr` must be an identifier
--> $DIR/enum.rs:20:1
|
20 | #[repr("foo")]
| ^^^^^^^^^^^^^^
error[E0552]: unrecognized representation hint
--> $DIR/enum.rs:29:8
|
29 | #[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`
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
error[E0566]: conflicting representation hints
--> $DIR/enum.rs:46:8
|
46 | #[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)]` (part of `#[deny(future_incompatible)]`) on by default
error[E0277]: the trait bound `UnsafeCell<()>: Immutable` is not satisfied
--> $DIR/enum.rs:64:10
|
64 | #[derive(Immutable)]
| ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<()>`
|
= note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<()>`
= help: the following other types implement trait `Immutable`:
&T
&mut T
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
and 137 others
= help: see issue #48214
= note: this error originates in the derive macro `Immutable` (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 `UnsafeCell<u8>: Immutable` is not satisfied
--> $DIR/enum.rs:75:10
|
75 | #[derive(Immutable)]
| ^^^^^^^^^ the trait `Immutable` is not implemented for `UnsafeCell<u8>`
|
= note: Consider adding `#[derive(Immutable)]` to `UnsafeCell<u8>`
= help: the following other types implement trait `Immutable`:
&T
&mut T
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
and 137 others
= help: see issue #48214
= note: this error originates in the derive macro `Immutable` (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 `NotTryFromBytes: TryFromBytes` is not satisfied
--> $DIR/enum.rs:104:10
|
104 | #[derive(TryFromBytes)]
| ^^^^^^^^^^^^ unsatisfied trait bound
|
help: the trait `TryFromBytes` is not implemented for `NotTryFromBytes`
--> $DIR/enum.rs:102:1
|
102 | struct NotTryFromBytes;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(TryFromBytes)]` to `NotTryFromBytes`
= help: the following other types implement trait `TryFromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 157 others
= help: see issue #48214
= note: this error originates in the derive macro `TryFromBytes` (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 `NotFromZeros: TryFromBytes` is not satisfied
--> $DIR/enum.rs:161:10
|
161 | #[derive(FromZeros)]
| ^^^^^^^^^ unsatisfied trait bound
|
help: the trait `TryFromBytes` is not implemented for `NotFromZeros`
--> $DIR/enum.rs:159:1
|
159 | struct NotFromZeros;
| ^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(TryFromBytes)]` to `NotFromZeros`
= help: the following other types implement trait `TryFromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 157 others
= help: see issue #48214
= note: this error originates in the derive macro `FromZeros` (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 `NotFromZeros: FromZeros` is not satisfied
--> $DIR/enum.rs:161:10
|
161 | #[derive(FromZeros)]
| ^^^^^^^^^ unsatisfied trait bound
|
help: the trait `FromZeros` is not implemented for `NotFromZeros`
--> $DIR/enum.rs:159:1
|
159 | struct NotFromZeros;
| ^^^^^^^^^^^^^^^^^^^
= note: Consider adding `#[derive(FromZeros)]` to `NotFromZeros`
= help: the following other types implement trait `FromZeros`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 142 others
= help: see issue #48214
= note: this error originates in the derive macro `FromZeros` (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 `bool: FromBytes` is not satisfied
--> $DIR/enum.rs:247:10
|
247 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= note: Consider adding `#[derive(FromBytes)]` to `bool`
= help: the following other types implement trait `FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 79 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]: `IntoBytes1` has 1 total byte(s) of padding
--> $DIR/enum.rs:623:10
|
623 | #[derive(IntoBytes)]
| ^^^^^^^^^ types with padding cannot implement `IntoBytes`
|
= note: consider using `zerocopy::Unalign` to lower the alignment of individual fields
= note: consider adding explicit fields where padding would be
= note: consider using `#[repr(packed)]` to remove padding
help: the trait `PaddingFree<IntoBytes1, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes1, 0>` is implemented for it
--> src/util/macro_util.rs:62:0
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (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]: `IntoBytes2` has 3 total byte(s) of padding
--> $DIR/enum.rs:638:10
|
638 | #[derive(IntoBytes)]
| ^^^^^^^^^ types with padding cannot implement `IntoBytes`
|
= note: consider using `zerocopy::Unalign` to lower the alignment of individual fields
= note: consider adding explicit fields where padding would be
= note: consider using `#[repr(packed)]` to remove padding
help: the trait `PaddingFree<IntoBytes2, 3>` is not implemented for `()`
but trait `PaddingFree<IntoBytes2, 0>` is implemented for it
--> src/util/macro_util.rs:62:0
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (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]: `IntoBytes3` has 2 total byte(s) of padding
--> $DIR/enum.rs:647:10
|
647 | #[derive(IntoBytes)]
| ^^^^^^^^^ types with padding cannot implement `IntoBytes`
|
= note: consider using `zerocopy::Unalign` to lower the alignment of individual fields
= note: consider adding explicit fields where padding would be
= note: consider using `#[repr(packed)]` to remove padding
help: the trait `PaddingFree<IntoBytes3, 2>` is not implemented for `()`
but trait `PaddingFree<IntoBytes3, 0>` is implemented for it
--> src/util/macro_util.rs:62:0
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (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: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/enum.rs:672:10
|
672 | #[derive(IntoBytes)]
| ^^^^^^^^^
|
note: not a concrete type
--> $DIR/enum.rs:672:10
|
672 | #[derive(IntoBytes)]
| ^^^^^^^^^
= note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `IntoBytes7` has 1 total byte(s) of padding
--> $DIR/enum.rs:681:10
|
681 | #[derive(IntoBytes)]
| ^^^^^^^^^ types with padding cannot implement `IntoBytes`
|
= note: consider using `zerocopy::Unalign` to lower the alignment of individual fields
= note: consider adding explicit fields where padding would be
= note: consider using `#[repr(packed)]` to remove padding
help: the trait `PaddingFree<IntoBytes7, 1>` is not implemented for `()`
but trait `PaddingFree<IntoBytes7, 0>` is implemented for it
--> src/util/macro_util.rs:62:0
= help: see issue #48214
= note: this error originates in the derive macro `IntoBytes` (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 `bool: FromBytes` is not satisfied
--> $DIR/enum.rs:247:10
|
247 | #[derive(FromBytes)]
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `bool`
|
= note: Consider adding `#[derive(FromBytes)]` to `bool`
= help: the following other types implement trait `FromBytes`:
()
(A, B)
(A, B, C)
(A, B, C, D)
(A, B, C, D, E)
(A, B, C, D, E, F)
(A, B, C, D, E, F, G)
(A, B, C, D, E, F, G, H)
and 79 others
note: required for `FooU8` to implement `FromBytes`
--> $DIR/enum.rs:247:10
|
247 | #[derive(FromBytes)]
| ^^^^^^^^^ unsatisfied trait bound introduced in this `derive` macro
note: required by a bound in `assert_is_from_bytes`
--> $DIR/enum.rs:247:10
|
247 | #[derive(FromBytes)]
| ^^^^^^^^^ required by this bound in `assert_is_from_bytes`
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 52 previous errors
Some errors have detailed explanations: E0277, E0552, E0565, E0566.
For more information about an error, try `rustc --explain E0277`.

688
vendor/zerocopy-derive/tests/ui/enum.rs vendored Normal file
View File

@@ -0,0 +1,688 @@
// 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_renamed;
fn main() {}
//
// Generic errors
//
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr("foo")]
//~[msrv, stable, nightly]^ ERROR: unrecognized representation hint
//~[msrv, stable, nightly]^^ ERROR: meta item in `repr` must be an identifier
enum Generic1 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(foo)]
//~[msrv, stable, nightly]^ ERROR: unrecognized representation hint
//~[msrv, stable, nightly]^^ ERROR: unrecognized representation hint
enum Generic2 {
A,
}
#[derive(FromBytes)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(transparent)]
enum Generic3 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, u16)]
//~[msrv, stable, nightly]^ ERROR: this conflicts with another representation hint
//~[msrv, stable, nightly]^^ ERROR: conflicting representation hints
enum Generic4 {
A,
}
#[derive(FromBytes)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
#[zerocopy(crate = "zerocopy_renamed")]
enum Generic5 {
A,
}
//
// Immutable errors
//
#[derive(Immutable)]
//~[msrv, stable, nightly]^ ERROR: the trait bound `UnsafeCell<()>: Immutable` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
enum Immutable1 {
A(core::cell::UnsafeCell<()>),
}
#[derive(Immutable)]
#[zerocopy(crate = "zerocopy_renamed")]
enum Never {}
#[derive(Immutable)]
//~[msrv, stable, nightly]^ ERROR: the trait bound `UnsafeCell<u8>: Immutable` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
enum Immutable2 {
Uninhabited(Never, core::cell::UnsafeCell<u8>),
Inhabited(u8),
}
//
// TryFromBytes errors
//
#[derive(TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
enum TryFromBytes1 {
A,
}
#[derive(TryFromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
enum TryFromBytes2 {
A,
B(u8),
}
struct NotTryFromBytes;
#[derive(TryFromBytes)]
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotTryFromBytes: TryFromBytes` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum TryFromBytes3 {
A(NotTryFromBytes),
}
//
// FromZeros errors
//
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
enum FromZeros1 {
A(u8),
}
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
enum FromZeros2 {
A,
B(u8),
}
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
enum FromZeros3 {
A = 1,
B,
}
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: FromZeros only supported on enums with a variant that has a discriminant of `0`
#[repr(u8)]
enum FromZeros4 {
A = 1,
B = 2,
}
const NEGATIVE_ONE: i8 = -1;
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: FromZeros only supported on enums with a variant that has a discriminant of `0`
#[repr(i8)]
enum FromZeros5 {
A = NEGATIVE_ONE,
B,
}
struct NotFromZeros;
#[derive(FromZeros)]
//~[msrv, stable, nightly]^ ERROR: the trait bound `NotFromZeros: TryFromBytes` is not satisfied
//~[msrv, stable, nightly]^^ ERROR: the trait bound `NotFromZeros: FromZeros` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum FromZeros6 {
A(NotFromZeros),
}
#[derive(FromZeros)]
#[zerocopy(crate = "zerocopy_renamed")]
//~[msrv, stable, nightly]^ ERROR: FromZeros only supported on enums with a variant that has a discriminant of `0`
#[repr(u8)]
enum FromZeros7 {
A = 1,
//~[msrv]^ ERROR: custom discriminant values are not allowed in enums with tuple or struct variants
B(NotFromZeros),
}
//
// FromBytes errors
//
#[derive(FromBytes)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
#[zerocopy(crate = "zerocopy_renamed")]
enum FromBytes1 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes2 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(usize)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes3 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(isize)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes4 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes5 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i32)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes6 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u64)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes7 {
A,
}
#[derive(FromBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i64)]
//~[msrv, stable, nightly]^ ERROR: `FromBytes` only supported on enums with `#[repr(...)]` attributes `u8`, `i8`, `u16`, or `i16`
enum FromBytes8 {
A,
}
#[derive(FromBytes)]
//~[msrv, stable, nightly]^ ERROR: the trait bound `bool: FromBytes` is not satisfied
//~[stable, nightly]^^ ERROR: the trait bound `bool: FromBytes` is not satisfied
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum FooU8 {
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,
Variant255(bool),
}
//
// Unaligned errors
//
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C)]
enum Unaligned1 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u16)]
enum Unaligned2 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i16)]
enum Unaligned3 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum Unaligned4 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i32)]
enum Unaligned5 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u64)]
enum Unaligned6 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i64)]
enum Unaligned7 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(usize)]
enum Unaligned8 {
A,
}
#[derive(Unaligned)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(u8)] or #[repr(i8)] attribute in order to guarantee this type's alignment
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(isize)]
enum Unaligned9 {
A,
}
#[derive(Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, align(2))]
//~[msrv, stable, nightly]^ ERROR: cannot derive `Unaligned` on type with alignment greater than 1
enum Unaligned10 {
A,
}
#[derive(Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(i8, align(2))]
//~[msrv, stable, nightly]^ ERROR: cannot derive `Unaligned` on type with alignment greater than 1
enum Unaligned11 {
A,
}
#[derive(Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(align(1), align(2))]
//~[msrv, stable, nightly]^ ERROR: this conflicts with another representation hint
enum Unaligned12 {
A,
}
#[derive(Unaligned)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(align(2), align(4))]
//~[msrv, stable, nightly]^ ERROR: this conflicts with another representation hint
enum Unaligned13 {
A,
}
//
// IntoBytes errors
//
#[derive(IntoBytes)]
//~[msrv]^ ERROR: the trait bound `(): PaddingFree<IntoBytes1, 1_usize>` is not satisfied
//~[stable, nightly]^^ ERROR: `IntoBytes1` has 1 total byte(s) of padding
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum IntoBytes1 {
A,
B(u8),
}
#[derive(IntoBytes)]
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(C, align(4))]
struct Align4IntoBytes(u32);
#[derive(IntoBytes)]
//~[msrv]^ ERROR: the trait bound `(): PaddingFree<IntoBytes2, 3_usize>` is not satisfied
//~[stable, nightly]^^ ERROR: `IntoBytes2` has 3 total byte(s) of padding
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum IntoBytes2 {
A(Align4IntoBytes),
}
#[derive(IntoBytes)]
//~[msrv]^ ERROR: the trait bound `(): PaddingFree<IntoBytes3, 2_usize>` is not satisfied
//~[stable, nightly]^^ ERROR: `IntoBytes3` has 2 total byte(s) of padding
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u32)]
enum IntoBytes3 {
A(u32),
B(u16),
}
#[derive(IntoBytes)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
#[zerocopy(crate = "zerocopy_renamed")]
enum IntoBytes4 {
A(u32),
B(u16),
}
#[derive(IntoBytes)]
//~[msrv, stable, nightly]^ ERROR: must have #[repr(C)] or #[repr(Int)] attribute in order to guarantee this type's memory layout
#[zerocopy(crate = "zerocopy_renamed")]
enum IntoBytes5 {
A(u32),
}
#[derive(IntoBytes)]
//~[msrv, stable, nightly]^ ERROR: generic `Self` types are currently not permitted in anonymous constants
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8)]
enum IntoBytes6<T> {
A(T),
//~[msrv, stable, nightly]^ ERROR: generic parameters may not be used in const operations
}
#[derive(IntoBytes)]
//~[msrv]^ ERROR: the trait bound `(): PaddingFree<IntoBytes7, 1_usize>` is not satisfied
//~[stable, nightly]^^ ERROR: `IntoBytes7` has 1 total byte(s) of padding
#[zerocopy(crate = "zerocopy_renamed")]
#[repr(u8, align(2))]
enum IntoBytes7 {
A,
}

Some files were not shown because too many files have changed in this diff Show More