11
11
/// Basic usage:
12
12
///
13
13
/// ```
14
+ /// #![feature(macro_metavar_expr)]
14
15
/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
15
16
///
16
17
/// #[derive(Copy, Clone, PartialEq, Debug)]
24
25
/// impl_tag! {
25
26
/// // The type for which the `Tag` will be implemented
26
27
/// 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
30
31
/// // 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
33
34
/// // 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
38
39
/// }
39
40
///
41
+ /// // Tag values are assigned in order:
40
42
/// assert_eq!(SomeTag::A.into_usize(), 0);
41
43
/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
42
44
/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
49
51
/// Structs are supported:
50
52
///
51
53
/// ```
54
+ /// #![feature(macro_metavar_expr)]
52
55
/// # use rustc_data_structures::impl_tag;
53
56
/// #[derive(Copy, Clone)]
54
57
/// struct Flags { a: bool, b: bool }
55
58
///
56
59
/// impl_tag! {
57
60
/// 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 },
62
65
/// }
63
66
/// ```
64
67
///
65
68
/// Not specifying all values results in a compile error:
66
69
///
67
70
/// ```compile_fail,E0004
71
+ /// #![feature(macro_metavar_expr)]
68
72
/// # use rustc_data_structures::impl_tag;
69
73
/// #[derive(Copy, Clone)]
70
74
/// enum E {
74
78
///
75
79
/// impl_tag! {
76
80
/// impl Tag for E;
77
- /// E::A <=> 0 ,
81
+ /// E::A,
78
82
/// }
79
83
/// ```
80
84
#[ macro_export]
81
85
macro_rules! impl_tag {
82
86
(
83
87
impl Tag for $Self: ty;
84
88
$(
85
- $( $path: ident) ::* $( { $( $fields: tt ) * } ) ? <=> $tag : literal ,
89
+ $( $path: ident) ::* $( { $( $fields: tt ) * } ) ?,
86
90
) *
87
91
) => {
88
92
// 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.
92
95
unsafe impl $crate:: tagged_ptr:: Tag for $Self {
93
96
const BITS : u32 = $crate:: tagged_ptr:: bits_for_tags( & [
94
- $( $tag, ) *
97
+ $(
98
+ ${ index( ) } ,
99
+ $( ${ ignore( path) } ) *
100
+ ) *
95
101
] ) ;
96
102
97
103
fn into_usize( self ) -> usize {
@@ -101,25 +107,22 @@ macro_rules! impl_tag {
101
107
match self {
102
108
// `match` is doing heavy lifting here, by requiring exhaustiveness
103
109
$(
104
- $( $path) ::* $( { $( $fields ) * } ) ? => $tag ,
110
+ $( $path) ::* $( { $( $fields ) * } ) ? => ${ index ( ) } ,
105
111
) *
106
112
}
107
113
}
108
114
109
115
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) ]
113
116
match tag {
114
117
$(
115
- $tag => $( $path) ::* $( { $( $fields ) * } ) ?,
118
+ ${ index ( ) } => $( $path) ::* $( { $( $fields ) * } ) ?,
116
119
) *
117
120
118
121
// 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.
123
126
_ => unsafe {
124
127
debug_assert!(
125
128
false ,
0 commit comments