1111/// Basic usage:
1212///
1313/// ```
14+ /// #![feature(macro_metavar_expr)]
1415/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
1516///
1617/// #[derive(Copy, Clone, PartialEq, Debug)]
2425/// impl_tag! {
2526/// // The type for which the `Tag` will be implemented
2627/// impl Tag for SomeTag;
27- /// // You need to specify the `{value_of_the_type} <=> { tag}` relationship
28- /// SomeTag::A <=> 0,
29- /// SomeTag::B <=> 1,
28+ /// // You need to specify all possible tag values:
29+ /// SomeTag::A, // 0
30+ /// SomeTag::B, // 1
3031/// // For variants with fields, you need to specify the fields:
31- /// SomeTag::X { v: true } <=> 2,
32- /// SomeTag::X { v: false } <=> 3,
32+ /// SomeTag::X { v: true }, // 2
33+ /// SomeTag::X { v: false }, // 3
3334/// // For tuple variants use named syntax:
34- /// SomeTag::Y { 0: true, 1: true } <=> 4,
35- /// SomeTag::Y { 0: false, 1: true } <=> 5,
36- /// SomeTag::Y { 0: true, 1: false } <=> 6,
37- /// SomeTag::Y { 0: false, 1: false } <=> 7,
35+ /// SomeTag::Y { 0: true, 1: true }, // 4
36+ /// SomeTag::Y { 0: false, 1: true }, // 5
37+ /// SomeTag::Y { 0: true, 1: false }, // 6
38+ /// SomeTag::Y { 0: false, 1: false }, // 7
3839/// }
3940///
41+ /// // Tag values are assigned in order:
4042/// assert_eq!(SomeTag::A.into_usize(), 0);
4143/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
4244/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
4951/// Structs are supported:
5052///
5153/// ```
54+ /// #![feature(macro_metavar_expr)]
5255/// # use rustc_data_structures::impl_tag;
5356/// #[derive(Copy, Clone)]
5457/// struct Flags { a: bool, b: bool }
5558///
5659/// impl_tag! {
5760/// impl Tag for Flags;
58- /// Flags { a: true, b: true } <=> 3 ,
59- /// Flags { a: false, b: true } <=> 2 ,
60- /// Flags { a: true, b: false } <=> 1 ,
61- /// Flags { a: false, b: false } <=> 0 ,
61+ /// Flags { a: true, b: true },
62+ /// Flags { a: false, b: true },
63+ /// Flags { a: true, b: false },
64+ /// Flags { a: false, b: false },
6265/// }
6366/// ```
6467///
6568/// Not specifying all values results in a compile error:
6669///
6770/// ```compile_fail,E0004
71+ /// #![feature(macro_metavar_expr)]
6872/// # use rustc_data_structures::impl_tag;
6973/// #[derive(Copy, Clone)]
7074/// enum E {
7478///
7579/// impl_tag! {
7680/// impl Tag for E;
77- /// E::A <=> 0 ,
81+ /// E::A,
7882/// }
7983/// ```
8084#[ macro_export]
8185macro_rules! impl_tag {
8286 (
8387 impl Tag for $Self: ty;
8488 $(
85- $( $path: ident) ::* $( { $( $fields: tt ) * } ) ? <=> $tag : literal ,
89+ $( $path: ident) ::* $( { $( $fields: tt ) * } ) ?,
8690 ) *
8791 ) => {
8892 // Safety:
89- // `into_usize` only returns one of `$tag`s,
90- // `bits_for_tags` is called on all `$tag`s,
91- // thus `BITS` constant is correct.
93+ // `bits_for_tags` is called on the same `${index()}`-es as
94+ // `into_usize` returns, thus `BITS` constant is correct.
9295 unsafe impl $crate:: tagged_ptr:: Tag for $Self {
9396 const BITS : u32 = $crate:: tagged_ptr:: bits_for_tags( & [
94- $( $tag, ) *
97+ $(
98+ ${ index( ) } ,
99+ $( ${ ignore( path) } ) *
100+ ) *
95101 ] ) ;
96102
97103 fn into_usize( self ) -> usize {
@@ -101,25 +107,22 @@ macro_rules! impl_tag {
101107 match self {
102108 // `match` is doing heavy lifting here, by requiring exhaustiveness
103109 $(
104- $( $path) ::* $( { $( $fields ) * } ) ? => $tag ,
110+ $( $path) ::* $( { $( $fields ) * } ) ? => ${ index ( ) } ,
105111 ) *
106112 }
107113 }
108114
109115 unsafe fn from_usize( tag: usize ) -> Self {
110- // Similarly to the above, this forbids repeating tags
111- // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
112- #[ forbid( unreachable_patterns) ]
113116 match tag {
114117 $(
115- $tag => $( $path) ::* $( { $( $fields ) * } ) ?,
118+ ${ index ( ) } => $( $path) ::* $( { $( $fields ) * } ) ?,
116119 ) *
117120
118121 // Safety:
119- // `into_usize` only returns one of `$tag`s,
120- // all `$tag`s are filtered up above,
121- // thus if this is reached, the safety contract of this
122- // function was already breached.
122+ // `into_usize` only returns `${index()}` of the same
123+ // repetition as we are filtering above, thus if this is
124+ // reached, the safety contract of this function was
125+ // already breached.
123126 _ => unsafe {
124127 debug_assert!(
125128 false ,
0 commit comments