diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index e7eecf7540ad7..8b8bda2e6b44f 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1475,6 +1475,7 @@ impl fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] +#[cfg_attr(not(bootstrap), repr(no_niche))] // rust-lang/rust#68303. pub struct UnsafeCell { value: T, } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ce7ddffd82584..bc3509b9b6507 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -135,6 +135,7 @@ #![feature(const_caller_location)] #![cfg_attr(bootstrap, feature(slice_patterns))] #![feature(assoc_int_consts)] +#![cfg_attr(not(bootstrap), feature(no_niche))] // rust-lang/rust#68303 #[prelude_import] #[allow(unused)] diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index acaa4eec9410d..ea1f7066c7562 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -356,12 +356,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { debug!("univariant offset: {:?} field: {:#?}", offset, field); offsets[i as usize] = offset; - if let Some(mut niche) = field.largest_niche.clone() { - let available = niche.available(dl); - if available > largest_niche_available { - largest_niche_available = available; - niche.offset += offset; - largest_niche = Some(niche); + if !repr.hide_niche() { + if let Some(mut niche) = field.largest_niche.clone() { + let available = niche.available(dl); + if available > largest_niche_available { + largest_niche_available = available; + niche.offset += offset; + largest_niche = Some(niche); + } } } @@ -838,7 +840,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Update `largest_niche` if we have introduced a larger niche. - let niche = Niche::from_scalar(dl, Size::ZERO, scalar.clone()); + let niche = if def.repr.hide_niche() { + None + } else { + Niche::from_scalar(dl, Size::ZERO, scalar.clone()) + }; if let Some(niche) = niche { match &st.largest_niche { Some(largest_niche) => { @@ -863,6 +869,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { return Ok(tcx.intern_layout(st)); } + // At this point, we have handled all unions and + // structs. (We have also handled univariant enums + // that allow representation optimization.) + assert!(def.is_enum()); + // The current code for niche-filling relies on variant indices // instead of actual discriminants, so dataful enums with // explicit discriminants (RFC #2363) would misbehave. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4889f751f601b..3579db777d793 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2036,7 +2036,8 @@ bitflags! { const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. const IS_LINEAR = 1 << 3; - + // If true, don't expose any niche to type's context. + const HIDE_NICHE = 1 << 4; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits | @@ -2073,6 +2074,7 @@ impl ReprOptions { ReprFlags::empty() } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, + attr::ReprNoNiche => ReprFlags::HIDE_NICHE, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { size = Some(i); @@ -2113,6 +2115,10 @@ impl ReprOptions { pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) } + #[inline] + pub fn hide_niche(&self) -> bool { + self.flags.contains(ReprFlags::HIDE_NICHE) + } pub fn discr_type(&self) -> attr::IntType { self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize)) diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index f8918016c1b98..76e4841d7ce21 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -824,7 +824,8 @@ fn find_repr_type_name(sess: &ParseSess, type_attrs: &[ast::Attribute]) -> &'sta attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) - | attr::ReprTransparent => continue, + | attr::ReprTransparent + | attr::ReprNoNiche => continue, attr::ReprC => "i32", diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index f20a57ea61c42..04d861418a8ad 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -204,6 +204,10 @@ declare_features! ( /// Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), + /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`, + /// it is not on path for eventual stabilization). + (active, no_niche, "1.42.0", None, None), + // no-tracking-issue-end // ------------------------------------------------------------------------- diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 3ff1ba3bbfc8c..81c5c3412b1db 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -16,9 +16,10 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::DUMMY_HIR_ID; use rustc_hir::{self, HirId, Item, ItemKind, TraitItem}; use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES}; +use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast::Attribute; +use syntax::ast::{Attribute, NestedMetaItem}; use syntax::attr; fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target { @@ -287,6 +288,21 @@ impl CheckAttrVisitor<'tcx> { _ => ("a", "struct, enum, or union"), } } + sym::no_niche => { + if !self.tcx.features().enabled(sym::no_niche) { + feature_err( + &self.tcx.sess.parse_sess, + sym::no_niche, + hint.span(), + "the attribute `repr(no_niche)` is currently unstable", + ) + .emit(); + } + match target { + Target::Struct | Target::Enum => continue, + _ => ("a", "struct or enum"), + } + } sym::i8 | sym::u8 | sym::i16 @@ -314,8 +330,10 @@ impl CheckAttrVisitor<'tcx> { // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. let hint_spans = hints.iter().map(|hint| hint.span()); - // Error on repr(transparent, ). - if is_transparent && hints.len() > 1 { + // Error on repr(transparent, ). + let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche; + let non_no_niche_count = hints.iter().filter(non_no_niche).count(); + if is_transparent && non_no_niche_count > 1 { let hint_spans: Vec<_> = hint_spans.clone().collect(); struct_span_err!( self.tcx.sess, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index e4f8b5a014389..f1bf746207a93 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -487,6 +487,7 @@ symbols! { None, non_exhaustive, non_modrs_mods, + no_niche, no_stack_check, no_start, no_std, @@ -583,6 +584,7 @@ symbols! { repr128, repr_align, repr_align_enum, + repr_no_niche, repr_packed, repr_simd, repr_transparent, diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 6cfe4f2de1e96..401e57b9a3c3f 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -820,6 +820,7 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(u32), + ReprNoNiche, } #[derive(Eq, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone, HashStable_Generic)] @@ -875,6 +876,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { sym::packed => Some(ReprPacked(1)), sym::simd => Some(ReprSimd), sym::transparent => Some(ReprTransparent), + sym::no_niche => Some(ReprNoNiche), name => int_type_of_word(name).map(ReprInt), }; diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs new file mode 100644 index 0000000000000..4ca3f7a1aad94 --- /dev/null +++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs @@ -0,0 +1,32 @@ +// For rust-lang/rust#68303: the contents of `UnsafeCell` cannot +// participate in the niche-optimization for enum discriminants. This +// test checks that an `Option>` has the same +// size in memory as an `Option>` (namely, 8 bytes). + +// run-pass + +#![feature(no_niche)] + +use std::cell::UnsafeCell; +use std::mem::size_of; +use std::num::NonZeroU32 as N32; + +struct Wrapper(T); + +#[repr(transparent)] +struct Transparent(T); + +#[repr(no_niche)] +struct NoNiche(T); + +fn main() { + assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); + + assert_eq!(size_of::>>(), 8); + assert_eq!(size_of::>>(), 8); +} diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs new file mode 100644 index 0000000000000..8872ee7119e4a --- /dev/null +++ b/src/test/ui/repr/feature-gate-no-niche.rs @@ -0,0 +1,20 @@ +use std::num::NonZeroU8 as N8; +use std::num::NonZeroU16 as N16; + +#[repr(no_niche)] +pub struct Cloaked(N16); +//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] + +#[repr(transparent, no_niche)] +pub struct Shadowy(N16); +//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] + +#[repr(no_niche)] +pub enum Cloaked1 { _A(N16), } +//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] + +#[repr(no_niche)] +pub enum Cloaked2 { _A(N16), _B(u8, N8) } +//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658] + +fn main() { } diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr new file mode 100644 index 0000000000000..34fd417cc99a2 --- /dev/null +++ b/src/test/ui/repr/feature-gate-no-niche.stderr @@ -0,0 +1,35 @@ +error[E0658]: the attribute `repr(no_niche)` is currently unstable + --> $DIR/feature-gate-no-niche.rs:4:8 + | +LL | #[repr(no_niche)] + | ^^^^^^^^ + | + = help: add `#![feature(no_niche)]` to the crate attributes to enable + +error[E0658]: the attribute `repr(no_niche)` is currently unstable + --> $DIR/feature-gate-no-niche.rs:8:21 + | +LL | #[repr(transparent, no_niche)] + | ^^^^^^^^ + | + = help: add `#![feature(no_niche)]` to the crate attributes to enable + +error[E0658]: the attribute `repr(no_niche)` is currently unstable + --> $DIR/feature-gate-no-niche.rs:12:8 + | +LL | #[repr(no_niche)] + | ^^^^^^^^ + | + = help: add `#![feature(no_niche)]` to the crate attributes to enable + +error[E0658]: the attribute `repr(no_niche)` is currently unstable + --> $DIR/feature-gate-no-niche.rs:16:8 + | +LL | #[repr(no_niche)] + | ^^^^^^^^ + | + = help: add `#![feature(no_niche)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs new file mode 100644 index 0000000000000..308634651a384 --- /dev/null +++ b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs @@ -0,0 +1,14 @@ +#![feature(no_niche)] + +use std::num::NonZeroU8 as N8; +use std::num::NonZeroU16 as N16; + +#[repr(no_niche)] +pub union Cloaked1 { _A: N16 } +//~^^ ERROR attribute should be applied to struct or enum [E0517] + +#[repr(no_niche)] +pub union Cloaked2 { _A: N16, _B: (u8, N8) } +//~^^ ERROR attribute should be applied to struct or enum [E0517] + +fn main() { } diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr new file mode 100644 index 0000000000000..4c542c5f0da64 --- /dev/null +++ b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr @@ -0,0 +1,19 @@ +error[E0517]: attribute should be applied to struct or enum + --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8 + | +LL | #[repr(no_niche)] + | ^^^^^^^^ +LL | pub union Cloaked1 { _A: N16 } + | ------------------------------ not a struct or enum + +error[E0517]: attribute should be applied to struct or enum + --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8 + | +LL | #[repr(no_niche)] + | ^^^^^^^^ +LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) } + | -------------------------------------------- not a struct or enum + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0517`. diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs new file mode 100644 index 0000000000000..a7f0d509af521 --- /dev/null +++ b/src/test/ui/repr/repr-no-niche.rs @@ -0,0 +1,329 @@ +// run-pass + +// This file tests repr(no_niche), which causes an struct/enum to hide +// any niche space that may exist in its internal state from the +// context it appears in. + +// Here are the axes this test is seeking to cover: +// +// repr annotation: +// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche) +// +// enum vs struct +// +// niche-type via type-parameter vs inline declaration + +#![feature(decl_macro)] +#![feature(no_niche)] + +use std::mem::size_of; +use std::num::{NonZeroU8, NonZeroU16}; + +mod struct_inline { + use std::num::NonZeroU16 as N16; + + #[derive(Debug)] pub struct Visible(N16); + + #[repr(no_niche)] + #[derive(Debug)] pub struct Cloaked(N16); + + #[repr(transparent)] + #[derive(Debug)] pub struct Transparent(N16); + + #[repr(transparent, no_niche)] + #[derive(Debug)] pub struct Shadowy(N16); +} + +mod struct_param { + #[derive(Debug)] pub struct Visible(T); + + #[repr(no_niche)] + #[derive(Debug)] pub struct Cloaked(T); + + #[repr(transparent)] + #[derive(Debug)] pub struct Transparent(T); + + #[repr(transparent, no_niche)] + #[derive(Debug)] pub struct Shadowy(T); +} + +mod enum_inline { + use crate::two_fifty_six_variant_enum; + use std::num::{NonZeroU8 as N8, NonZeroU16 as N16}; + + #[derive(Debug)] pub enum Visible1 { _A(N16), } + + #[repr(no_niche)] + #[derive(Debug)] pub enum Cloaked1 { _A(N16), } + + // (N.B.: transparent enums must be univariant) + #[repr(transparent)] + #[derive(Debug)] pub enum Transparent { _A(N16), } + + #[repr(transparent, no_niche)] + #[derive(Debug)] pub enum Shadowy { _A(N16), } + + // including multivariant enums for completeness. Payload and + // number of variants (i.e. discriminant size) have been chosen so + // that layout including discriminant is 4 bytes, with no space in + // padding to hide another discrimnant from the surrounding + // context. + // + // (Note that multivariant enums cannot usefully expose a niche in + // general; this test is relying on that.) + two_fifty_six_variant_enum!(Visible2, N8); + + #[repr(no_niche)] + two_fifty_six_variant_enum!(Cloaked2, N8); +} + +mod enum_param { + use super::two_fifty_six_variant_enum; + + #[derive(Debug)] pub enum Visible1 { _A(T), } + + #[repr(no_niche)] + #[derive(Debug)] pub enum Cloaked1 { _A(T), } + + // (N.B.: transparent enums must be univariant) + #[repr(transparent)] + #[derive(Debug)] pub enum Transparent { _A(T), } + + #[repr(transparent, no_niche)] + #[derive(Debug)] pub enum Shadowy { _A(T), } + + // including multivariant enums for completeness. Same notes apply + // here as above (assuming `T` is instantiated with `NonZeroU8`). + two_fifty_six_variant_enum!(Visible2); + + #[repr(no_niche)] + two_fifty_six_variant_enum!(Cloaked2); +} + +fn main() { + // sanity-checks + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 2); + + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 2); // transparent enums are univariant + assert_eq!(size_of::(), 2); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 4); + + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 4); + assert_eq!(size_of::>(), 4); + + // now the actual tests of no_niche: how do inputs above compose + // with `Option` type constructor. The cases with a `_+2` are the + // ones where no_niche fires. + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2+2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2+2); + + assert_eq!(size_of::>>(), 2); + assert_eq!(size_of::>>(), 2+2); + assert_eq!(size_of::>>(), 2); + assert_eq!(size_of::>>(), 2+2); + + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2+2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2+2); + // cannot use niche of multivariant payload + assert_eq!(size_of::>(), 4+2); + assert_eq!(size_of::>(), 4+2); + + assert_eq!(size_of::>>(), 2); + assert_eq!(size_of::>>(), 2+2); + assert_eq!(size_of::>>(), 2); + assert_eq!(size_of::>>(), 2+2); + // cannot use niche of multivariant payload + assert_eq!(size_of::>>(), 4+2); + assert_eq!(size_of::>>(), 4+2); +} + +macro two_fifty_six_variant_enum { + ($name:ident<$param:ident>) => { + #[derive(Debug)] + pub enum $name<$param> { + _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), + _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), + _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), + _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), + + _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), + _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), + _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), + _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), + + _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), + _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), + _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), + _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), + + _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), + _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), + _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), + _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), + + _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), + _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), + _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), + _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), + + _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), + _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), + _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), + _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), + + _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), + _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), + _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), + _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), + + _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), + _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), + _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), + _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), + + _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), + _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), + _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), + _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), + + _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), + _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), + _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), + _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), + + _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), + _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), + _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), + _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), + + _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), + _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), + _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), + _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), + + _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), + _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), + _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), + _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), + + _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), + _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), + _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), + _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), + + _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), + _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), + _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), + _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), + + _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), + _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), + _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), + _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), + } + }, + + ($name:ident, $param:ty) => { + #[derive(Debug)] + pub enum $name { + _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param), + _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param), + _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param), + _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param), + + _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param), + _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param), + _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param), + _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param), + + _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param), + _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param), + _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param), + _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param), + + _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param), + _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param), + _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param), + _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param), + + _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param), + _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param), + _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param), + _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param), + + _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param), + _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param), + _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param), + _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param), + + _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param), + _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param), + _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param), + _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param), + + _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param), + _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param), + _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param), + _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param), + + _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param), + _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param), + _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param), + _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param), + + _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param), + _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param), + _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param), + _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param), + + _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param), + _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param), + _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param), + _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param), + + _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param), + _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param), + _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param), + _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param), + + _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param), + _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param), + _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param), + _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param), + + _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param), + _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param), + _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param), + _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param), + + _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param), + _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param), + _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param), + _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param), + + _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param), + _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param), + _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param), + _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param), + } + } +}