diff --git a/zerocopy/src/macros.rs b/zerocopy/src/macros.rs index bae08d19cc..91971aee90 100644 --- a/zerocopy/src/macros.rs +++ b/zerocopy/src/macros.rs @@ -988,36 +988,183 @@ macro_rules! include_value { #[doc(hidden)] #[macro_export] macro_rules! cryptocorrosion_derive_traits { + // EMISSION INVARIANT: If an unsafe impl emitted by this macro is compiled, + // the type declaration whose fields supplied that impl's bounds is + // compiled in the same `@emit` expansion. Every `cfg` predicate gates the + // single invocation which emits the representation check, type, and every + // unsafe impl. The remaining attributes are normalized to `derive`, + // `allow`, and `doc`, none of which can remove the type. Field types are + // restricted to a macro-free grammar, so that repeating their tokens in + // the declaration and impl bounds cannot expand to different types. The + // internal `@emit` arms validate these restrictions themselves because + // every arm of an exported `macro_rules!` macro is callable by downstream + // code. ( #[repr($repr:ident)] - $(#[$attr:meta])* + $($rest:tt)* + ) => { + $crate::cryptocorrosion_derive_traits! { + @parse + [$repr] + [] + [] + $($rest)* + } + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[cfg($($next_cfg:tt)*)] + $($rest:tt)* + ) => { + $crate::cryptocorrosion_derive_traits! { + @parse + [$repr] + [$({ $($cfg)* })* { $($next_cfg)* }] + [$($attrs)*] + $($rest)* + } + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[derive($($next_derive:tt)*)] + $($rest:tt)* + ) => { + $crate::cryptocorrosion_derive_traits! { + @parse + [$repr] + [$({ $($cfg)* })*] + [$($attrs)* (derive ($($next_derive)*))] + $($rest)* + } + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[allow($($next_allow:tt)*)] + $($rest:tt)* + ) => { + $crate::cryptocorrosion_derive_traits! { + @parse + [$repr] + [$({ $($cfg)* })*] + [$($attrs)* (allow ($($next_allow)*))] + $($rest)* + } + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[doc $($next_doc:tt)*] + $($rest:tt)* + ) => { + $crate::cryptocorrosion_derive_traits! { + @parse + [$repr] + [$({ $($cfg)* })*] + [$($attrs)* (doc [$($next_doc)*])] + $($rest)* + } + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[cfg_attr($($cfg_attr:tt)*)] + $($rest:tt)* + ) => { + compile_error!( + "`cryptocorrosion_derive_traits!` does not support `cfg_attr`; use direct `cfg` attributes" + ); + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + #[$($attr:tt)*] + $($rest:tt)* + ) => { + compile_error!( + "`cryptocorrosion_derive_traits!` only supports `cfg`, `derive`, `allow`, and `doc` attributes" + ); + }; + ( + @parse + [$repr:ident] + [$({ $($cfg:tt)* })*] + [$($attrs:tt)*] + $($item:tt)* + ) => { + $(#[cfg($($cfg)*)])* + $crate::cryptocorrosion_derive_traits! { + @emit + [$repr] + [$($attrs)*] + $($item)* + } + }; + ( + @emit + [$repr:ident] + [$(( $(derive ($($derive:tt)*))? $(allow ($($allow:tt)*))? $(doc [$($doc:tt)*])? ))*] $vis:vis struct $name:ident $(<$($tyvar:ident),*>)? $( ( - $($tuple_field_vis:vis $tuple_field_ty:ty),* + $( + $tuple_field_vis:vis + $([$tuple_field_array_element:ident; $tuple_field_array_len:literal])? + $($tuple_field_path:ident $(<$($tuple_field_arg:ident),*>)?)? + ),* ); )? $( { - $($field_vis:vis $field_name:ident: $field_ty:ty,)* + $( + $field_vis:vis $field_name:ident: + $([$field_array_element:ident; $field_array_len:literal])? + $($field_path:ident $(<$($field_arg:ident),*>)?)?, + )* } )? ) => { $crate::cryptocorrosion_derive_traits!(@assert_allowed_struct_repr #[repr($repr)]); - $(#[$attr])* + $( + $(#[derive($($derive)*)])? + $(#[allow($($allow)*)])? + $(#[doc $($doc)*])? + )* #[repr($repr)] $vis struct $name $(<$($tyvar),*>)? $( ( - $($tuple_field_vis $tuple_field_ty),* + $( + $tuple_field_vis + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ),* ); )? $( { - $($field_vis $field_name: $field_ty,)* + $( + $field_vis $field_name: + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)?, + )* } )? @@ -1025,11 +1172,23 @@ macro_rules! cryptocorrosion_derive_traits { unsafe impl $(<$($tyvar),*>)? $crate::TryFromBytes for $name$(<$($tyvar),*>)? where $( - $($tuple_field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ): $crate::FromBytes, + )* )? $( - $($field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, + )* )? { #[inline(always)] @@ -1040,8 +1199,9 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block // requires all field types to be `FromBytes`. Thus, all - // initialized byte sequences constitutes valid instances of - // `Self`. + // initialized byte sequences constitute valid instances of + // `Self`. The emission invariant ensures that `Self` is the + // type declaration whose fields supplied these bounds. true } @@ -1051,14 +1211,28 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `FromBytes`, which is a sub-trait of `FromZeros`. + // The emission invariant ensures that `Self` is the type declaration + // whose fields supplied these bounds. unsafe impl $(<$($tyvar),*>)? $crate::FromZeros for $name$(<$($tyvar),*>)? where $( - $($tuple_field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ): $crate::FromBytes, + )* )? $( - $($field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, + )* )? { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1066,15 +1240,28 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all - // field types to be `FromBytes`. + // field types to be `FromBytes`. The emission invariant ensures that + // `Self` is the type declaration whose fields supplied these bounds. unsafe impl $(<$($tyvar),*>)? $crate::FromBytes for $name$(<$($tyvar),*>)? where $( - $($tuple_field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ): $crate::FromBytes, + )* )? $( - $($field_ty: $crate::FromBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, + )* )? { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1082,16 +1269,29 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, this `impl` block requires all field - // types to be `IntoBytes`, and a padding check is used to ensures that - // there are no padding bytes. + // types to be `IntoBytes`, and a padding check is used to ensure that + // there are no padding bytes. The emission invariant ensures that + // `Self` is the type declaration whose fields supplied these bounds. unsafe impl $(<$($tyvar),*>)? $crate::IntoBytes for $name$(<$($tyvar),*>)? where $( - $($tuple_field_ty: $crate::IntoBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ): $crate::IntoBytes, + )* )? $( - $($field_ty: $crate::IntoBytes,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::IntoBytes, + )* )? (): $crate::util::macro_util::PaddingFree< @@ -1099,8 +1299,20 @@ macro_rules! cryptocorrosion_derive_traits { { $crate::cryptocorrosion_derive_traits!( @struct_padding_check #[repr($repr)] - $(($($tuple_field_ty),*))? - $({$($field_ty),*})? + $(($( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ) + ),*))? + $({$( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ) + ),*})? ) }, >, @@ -1110,20 +1322,60 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all - // field types to be `Immutable`. + // field types to be `Immutable`. The emission invariant ensures that + // `Self` is the type declaration whose fields supplied these bounds. unsafe impl $(<$($tyvar),*>)? $crate::Immutable for $name$(<$($tyvar),*>)? where $( - $($tuple_field_ty: $crate::Immutable,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$tuple_field_array_element; $tuple_field_array_len])? + $($tuple_field_path $(<$($tuple_field_arg),*>)?)? + ): $crate::Immutable, + )* )? $( - $($field_ty: $crate::Immutable,)* + $( + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::Immutable, + )* )? { fn only_derive_is_allowed_to_implement_this_trait() {} } }; + ( + @emit + [$repr:ident] + [$(( $(derive ($($derive:tt)*))? $(allow ($($allow:tt)*))? $(doc [$($doc:tt)*])? ))*] + $vis:vis struct $name:ident $(<$($tyvar:ident),*>)? + $( + ( + $($tuple_field_vis:vis $tuple_field_ty:ty),* + ); + )? + + $( + { + $($field_vis:vis $field_name:ident: $field_ty:ty,)* + } + )? + ) => { + compile_error!( + "`cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths" + ); + }; + (@field_type [$element:ident; $len:literal]) => { + [$element; $len] + }; + (@field_type $path:ident $(<$($arg:ident),*>)?) => { + $path $(<$($arg),*>)? + }; (@assert_allowed_struct_repr #[repr(transparent)]) => {}; (@assert_allowed_struct_repr #[repr(C)]) => {}; (@assert_allowed_struct_repr #[$_attr:meta]) => { @@ -1155,19 +1407,28 @@ macro_rules! cryptocorrosion_derive_traits { ) }; ( - #[repr(C)] - $(#[$attr:meta])* + @emit + [C] + [$(( $(derive ($($derive:tt)*))? $(allow ($($allow:tt)*))? $(doc [$($doc:tt)*])? ))*] $vis:vis union $name:ident { $( - $field_name:ident: $field_ty:ty, + $field_name:ident: + $([$field_array_element:ident; $field_array_len:literal])? + $($field_path:ident $(<$($field_arg:ident),*>)?)?, )* } ) => { - $(#[$attr])* + $( + $(#[derive($($derive)*)])? + $(#[allow($($allow)*)])? + $(#[doc $($doc)*])? + )* #[repr(C)] $vis union $name { $( - $field_name: $field_ty, + $field_name: + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)?, )* } @@ -1175,7 +1436,11 @@ macro_rules! cryptocorrosion_derive_traits { unsafe impl $crate::TryFromBytes for $name where $( - $field_ty: $crate::FromBytes, + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, )* { #[inline(always)] @@ -1185,8 +1450,10 @@ macro_rules! cryptocorrosion_derive_traits { { // SAFETY: This macro only accepts `#[repr(C)]` unions, and this // `impl` block requires all field types to be `FromBytes`. - // Thus, all initialized byte sequences constitutes valid - // instances of `Self`. + // Thus, all initialized byte sequences constitute valid + // instances of `Self`. The emission invariant ensures that + // `Self` is the type declaration whose fields supplied these + // bounds. true } @@ -1195,22 +1462,33 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `FromBytes`, which is a - // sub-trait of `FromZeros`. + // sub-trait of `FromZeros`. The emission invariant ensures that `Self` + // is the type declaration whose fields supplied these bounds. unsafe impl $crate::FromZeros for $name where $( - $field_ty: $crate::FromBytes, + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, )* { fn only_derive_is_allowed_to_implement_this_trait() {} } // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` - // block requires all field types to be `FromBytes`. + // block requires all field types to be `FromBytes`. The emission + // invariant ensures that `Self` is the type declaration whose fields + // supplied these bounds. unsafe impl $crate::FromBytes for $name where $( - $field_ty: $crate::FromBytes, + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::FromBytes, )* { fn only_derive_is_allowed_to_implement_this_trait() {} @@ -1218,12 +1496,17 @@ macro_rules! cryptocorrosion_derive_traits { // SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl` // block requires all field types to be `IntoBytes`, and a padding check - // is used to ensures that there are no padding bytes before or after - // any field. + // is used to ensure that there are no padding bytes before or after + // any field. The emission invariant ensures that `Self` is the type + // declaration whose fields supplied these bounds. unsafe impl $crate::IntoBytes for $name where $( - $field_ty: $crate::IntoBytes, + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::IntoBytes, )* (): $crate::util::macro_util::PaddingFree< Self, @@ -1232,7 +1515,11 @@ macro_rules! cryptocorrosion_derive_traits { Self, None::, None::, - [$($field_ty),*] + [$($crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + )),*] ) }, >, @@ -1241,16 +1528,36 @@ macro_rules! cryptocorrosion_derive_traits { } // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` - // block requires all field types to be `Immutable`. + // block requires all field types to be `Immutable`. The emission + // invariant ensures that `Self` is the type declaration whose fields + // supplied these bounds. unsafe impl $crate::Immutable for $name where $( - $field_ty: $crate::Immutable, + $crate::cryptocorrosion_derive_traits!( + @field_type + $([$field_array_element; $field_array_len])? + $($field_path $(<$($field_arg),*>)?)? + ): $crate::Immutable, )* { fn only_derive_is_allowed_to_implement_this_trait() {} } }; + ( + @emit + [C] + [$(( $(derive ($($derive:tt)*))? $(allow ($($allow:tt)*))? $(doc [$($doc:tt)*])? ))*] + $vis:vis union $name:ident { + $( + $field_name:ident: $field_ty:ty, + )* + } + ) => { + compile_error!( + "`cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths" + ); + }; } #[cfg(test)] @@ -1822,4 +2129,82 @@ mod tests { pub struct ReprC(u8, u8, u16); } } + + #[allow(dead_code)] + mod cryptocorrosion_cfg_false_struct { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + cryptocorrosion_derive_traits! { + #[repr(C)] + #[derive(Copy, Clone)] + #[cfg(any())] + #[allow(non_camel_case_types)] + /// This definition and all of its impls are disabled. + struct Packet(u8); + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); + } + + #[allow(dead_code)] + mod cryptocorrosion_cfg_false_union { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + cryptocorrosion_derive_traits! { + #[repr(C)] + #[derive(Copy, Clone)] + #[cfg(any())] + #[allow(non_camel_case_types)] + /// This definition and all of its impls are disabled. + union Packet { + byte: u8, + } + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); + } + + #[allow(dead_code)] + mod cryptocorrosion_cfg_true { + #![deny(non_camel_case_types)] + + use super::*; + + cryptocorrosion_derive_traits! { + #[repr(transparent)] + #[derive(Copy, Clone)] + #[cfg(all())] + #[allow(non_camel_case_types)] + /// This definition and all of its impls are enabled. + struct cfg_true_struct(u8); + } + + cryptocorrosion_derive_traits! { + #[repr(C)] + #[derive(Copy, Clone)] + #[cfg(all())] + #[allow(non_camel_case_types)] + /// This definition and all of its impls are enabled. + union cfg_true_union { + byte: u8, + } + } + + static_assertions::assert_impl_all!( + cfg_true_struct: Copy, Clone, TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); + static_assertions::assert_impl_all!( + cfg_true_union: Copy, Clone, TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); + } } diff --git a/zerocopy/tests/ui/cryptocorrosion-cfg.rs b/zerocopy/tests/ui/cryptocorrosion-cfg.rs new file mode 100644 index 0000000000..35f4ec471d --- /dev/null +++ b/zerocopy/tests/ui/cryptocorrosion-cfg.rs @@ -0,0 +1,139 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//@[msrv, stable, nightly] check-pass + +#![allow(dead_code)] +#![forbid(unsafe_code)] + +use zerocopy::{FromBytes, FromZeros, Immutable, IntoBytes, TryFromBytes}; + +mod struct_definition { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + zerocopy::cryptocorrosion_derive_traits! { + #[repr(C)] + #[cfg(any())] + struct Packet(u8); + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); +} + +mod union_definition { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + zerocopy::cryptocorrosion_derive_traits! { + #[repr(C)] + #[cfg(any())] + union Packet { + byte: u8, + } + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); +} + +mod direct_parse_struct_definition { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + zerocopy::cryptocorrosion_derive_traits! { + @parse + [C] + [{ all() } { any() }] + [(derive (Copy, Clone)) (allow (dead_code)) (doc [= "disabled"])] + struct Packet(u8); + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); +} + +mod direct_parse_union_definition { + use super::*; + + #[repr(transparent)] + struct Packet(bool); + + zerocopy::cryptocorrosion_derive_traits! { + @parse + [C] + [{ all() } { any() }] + [(derive (Copy, Clone)) (allow (dead_code)) (doc [= "disabled"])] + union Packet { + byte: u8, + } + } + + static_assertions::assert_not_impl_any!( + Packet: TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); +} + +mod complete_expansion { + zerocopy::cryptocorrosion_derive_traits! { + #[repr(Rust)] + #[cfg(any())] + struct DisabledInvalidStructRepr(u8); + } + + zerocopy::cryptocorrosion_derive_traits! { + #[repr(Rust)] + #[cfg(any())] + union DisabledInvalidUnionRepr { + byte: u8, + } + } +} + +mod cfg_true { + use super::*; + + zerocopy::cryptocorrosion_derive_traits! { + #[repr(transparent)] + #[derive(Copy, Clone)] + #[cfg(all())] + #[allow(non_camel_case_types)] + /// The declaration and all five impls are enabled together. + struct enabled_struct(u8); + } + + zerocopy::cryptocorrosion_derive_traits! { + #[repr(C)] + #[derive(Copy, Clone)] + #[cfg(all())] + #[allow(non_camel_case_types)] + /// The declaration and all five impls are enabled together. + union enabled_union { + byte: u8, + } + } + + static_assertions::assert_impl_all!( + enabled_struct: Copy, Clone, TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); + static_assertions::assert_impl_all!( + enabled_union: Copy, Clone, TryFromBytes, FromZeros, FromBytes, IntoBytes, Immutable + ); +} + +fn main() {} diff --git a/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.msrv.stderr b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.msrv.stderr new file mode 100644 index 0000000000..66499fbfae --- /dev/null +++ b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.msrv.stderr @@ -0,0 +1,105 @@ +error: `cryptocorrosion_derive_traits!` does not support `cfg_attr`; use direct `cfg` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:21:1 + | +21 | / zerocopy::cryptocorrosion_derive_traits! { +22 | | #[repr(C)] +23 | | #[cfg_attr(all(), cfg(any()))] +24 | | struct CfgAttr(u8); +25 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports `cfg`, `derive`, `allow`, and `doc` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:27:1 + | +27 | / zerocopy::cryptocorrosion_derive_traits! { +28 | | #[repr(C)] +29 | | #[deprecated] +30 | | struct Unsupported(u8); +31 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:38:1 + | +38 | / zerocopy::cryptocorrosion_derive_traits! { +39 | | #[repr(C)] +40 | | struct MacroStruct(field_type!()); +41 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:43:1 + | +43 | / zerocopy::cryptocorrosion_derive_traits! { +44 | | #[repr(C)] +45 | | union MacroUnion { +46 | | byte: field_type!(), +47 | | } +48 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:50:1 + | +50 | / zerocopy::cryptocorrosion_derive_traits! { +51 | | @emit +52 | | [C] +53 | | [] +54 | | struct DirectMacroStruct(field_type!()); +55 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:57:1 + | +57 | / zerocopy::cryptocorrosion_derive_traits! { +58 | | @emit +59 | | [C] +60 | | [] +... | +63 | | } +64 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:66:1 + | +66 | / zerocopy::cryptocorrosion_derive_traits! { +67 | | @parse +68 | | [C] +69 | | [{ all() }] +70 | | [(doc [= "forwarded"])] +71 | | struct DirectParseMacroStruct(field_type!()); +72 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:74:1 + | +74 | / zerocopy::cryptocorrosion_derive_traits! { +75 | | @parse +76 | | [C] +77 | | [{ all() }] +... | +81 | | } +82 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + diff --git a/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.nightly.stderr b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.nightly.stderr new file mode 100644 index 0000000000..3e69fd7991 --- /dev/null +++ b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.nightly.stderr @@ -0,0 +1,103 @@ +error: `cryptocorrosion_derive_traits!` does not support `cfg_attr`; use direct `cfg` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:21:1 + | +21 | / zerocopy::cryptocorrosion_derive_traits! { +22 | | #[repr(C)] +23 | | #[cfg_attr(all(), cfg(any()))] +24 | | struct CfgAttr(u8); +25 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports `cfg`, `derive`, `allow`, and `doc` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:27:1 + | +27 | / zerocopy::cryptocorrosion_derive_traits! { +28 | | #[repr(C)] +29 | | #[deprecated] +30 | | struct Unsupported(u8); +31 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:38:1 + | +38 | / zerocopy::cryptocorrosion_derive_traits! { +39 | | #[repr(C)] +40 | | struct MacroStruct(field_type!()); +41 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:43:1 + | +43 | / zerocopy::cryptocorrosion_derive_traits! { +44 | | #[repr(C)] +45 | | union MacroUnion { +46 | | byte: field_type!(), +47 | | } +48 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:50:1 + | +50 | / zerocopy::cryptocorrosion_derive_traits! { +51 | | @emit +52 | | [C] +53 | | [] +54 | | struct DirectMacroStruct(field_type!()); +55 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:57:1 + | +57 | / zerocopy::cryptocorrosion_derive_traits! { +58 | | @emit +59 | | [C] +60 | | [] +... | +64 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:66:1 + | +66 | / zerocopy::cryptocorrosion_derive_traits! { +67 | | @parse +68 | | [C] +69 | | [{ all() }] +70 | | [(doc [= "forwarded"])] +71 | | struct DirectParseMacroStruct(field_type!()); +72 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:74:1 + | +74 | / zerocopy::cryptocorrosion_derive_traits! { +75 | | @parse +76 | | [C] +77 | | [{ all() }] +... | +82 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + diff --git a/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.rs b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.rs new file mode 100644 index 0000000000..2a9563d733 --- /dev/null +++ b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.rs @@ -0,0 +1,84 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +#![allow(dead_code, unused_macros)] +#![forbid(unsafe_code)] + +macro_rules! field_type { + () => { + u8 + }; +} + +#[repr(transparent)] +struct CfgAttr(bool); + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` does not support `cfg_attr` + #[repr(C)] + #[cfg_attr(all(), cfg(any()))] + struct CfgAttr(u8); +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports `cfg`, `derive`, `allow`, and `doc` attributes + #[repr(C)] + #[deprecated] + struct Unsupported(u8); +} + +// A captured type fragment is expanded separately each time it is +// transcribed. In particular, a stateful function-like proc macro could +// expand to different types in the declaration and the unsafe impl bounds. +// Reject all type macros, including through the directly callable internal +// emitter arms. A declarative macro is sufficient to exercise that syntax. +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + #[repr(C)] + struct MacroStruct(field_type!()); +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + #[repr(C)] + union MacroUnion { + byte: field_type!(), + } +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + @emit + [C] + [] + struct DirectMacroStruct(field_type!()); +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + @emit + [C] + [] + union DirectMacroUnion { + byte: field_type!(), + } +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + @parse + [C] + [{ all() }] + [(doc [= "forwarded"])] + struct DirectParseMacroStruct(field_type!()); +} + +zerocopy::cryptocorrosion_derive_traits! { //~[msrv, stable, nightly] ERROR: `cryptocorrosion_derive_traits!` only supports field types + @parse + [C] + [{ all() }] + [(doc [= "forwarded"])] + union DirectParseMacroUnion { + byte: field_type!(), + } +} + +fn main() {} diff --git a/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.stable.stderr b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.stable.stderr new file mode 100644 index 0000000000..3e69fd7991 --- /dev/null +++ b/zerocopy/tests/ui/cryptocorrosion-unsupported-attributes.stable.stderr @@ -0,0 +1,103 @@ +error: `cryptocorrosion_derive_traits!` does not support `cfg_attr`; use direct `cfg` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:21:1 + | +21 | / zerocopy::cryptocorrosion_derive_traits! { +22 | | #[repr(C)] +23 | | #[cfg_attr(all(), cfg(any()))] +24 | | struct CfgAttr(u8); +25 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports `cfg`, `derive`, `allow`, and `doc` attributes + --> $DIR/cryptocorrosion-unsupported-attributes.rs:27:1 + | +27 | / zerocopy::cryptocorrosion_derive_traits! { +28 | | #[repr(C)] +29 | | #[deprecated] +30 | | struct Unsupported(u8); +31 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:38:1 + | +38 | / zerocopy::cryptocorrosion_derive_traits! { +39 | | #[repr(C)] +40 | | struct MacroStruct(field_type!()); +41 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:43:1 + | +43 | / zerocopy::cryptocorrosion_derive_traits! { +44 | | #[repr(C)] +45 | | union MacroUnion { +46 | | byte: field_type!(), +47 | | } +48 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:50:1 + | +50 | / zerocopy::cryptocorrosion_derive_traits! { +51 | | @emit +52 | | [C] +53 | | [] +54 | | struct DirectMacroStruct(field_type!()); +55 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:57:1 + | +57 | / zerocopy::cryptocorrosion_derive_traits! { +58 | | @emit +59 | | [C] +60 | | [] +... | +64 | | } + | |_^ + | + = note: this error originates in the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:66:1 + | +66 | / zerocopy::cryptocorrosion_derive_traits! { +67 | | @parse +68 | | [C] +69 | | [{ all() }] +70 | | [(doc [= "forwarded"])] +71 | | struct DirectParseMacroStruct(field_type!()); +72 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `cryptocorrosion_derive_traits!` only supports field types composed of identifiers, identifier generic arguments, and arrays with literal lengths + --> $DIR/cryptocorrosion-unsupported-attributes.rs:74:1 + | +74 | / zerocopy::cryptocorrosion_derive_traits! { +75 | | @parse +76 | | [C] +77 | | [{ all() }] +... | +82 | | } + | |_^ + | + = note: this error originates in the macro `$crate::cryptocorrosion_derive_traits` which comes from the expansion of the macro `zerocopy::cryptocorrosion_derive_traits` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors +