Skip to content

Commit ff49db4

Browse files
committed
Fix CI
1 parent b01220c commit ff49db4

File tree

1 file changed

+153
-0
lines changed
  • compiler/rustc_data_structures/src/tagged_ptr

1 file changed

+153
-0
lines changed

compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs

+153
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
/// E::A,
8282
/// }
8383
/// ```
84+
#[cfg(bootstrap)]
8485
#[macro_export]
8586
macro_rules! impl_tag {
8687
(
@@ -93,12 +94,20 @@ macro_rules! impl_tag {
9394
// `bits_for_tags` is called on the same `${index()}`-es as
9495
// `into_usize` returns, thus `BITS` constant is correct.
9596
unsafe impl $crate::tagged_ptr::Tag for $Self {
97+
#[cfg(bootstrap)]
9698
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
9799
$(
98100
${index()},
99101
$( ${ignore(path)} )*
100102
)*
101103
]);
104+
#[cfg(not(bootstrap))]
105+
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
106+
$(
107+
${index()},
108+
$( ${ignore($path)} )*
109+
)*
110+
]);
102111

103112
#[inline]
104113
fn into_usize(self) -> usize {
@@ -140,5 +149,149 @@ macro_rules! impl_tag {
140149
};
141150
}
142151

152+
/// Implements [`Tag`] for a given type.
153+
///
154+
/// You can use `impl_tag` on structs and enums.
155+
/// You need to specify the type and all its possible values,
156+
/// which can only be paths with optional fields.
157+
///
158+
/// [`Tag`]: crate::tagged_ptr::Tag
159+
///
160+
/// # Examples
161+
///
162+
/// Basic usage:
163+
///
164+
/// ```
165+
/// #![feature(macro_metavar_expr)]
166+
/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
167+
///
168+
/// #[derive(Copy, Clone, PartialEq, Debug)]
169+
/// enum SomeTag {
170+
/// A,
171+
/// B,
172+
/// X { v: bool },
173+
/// Y(bool, bool),
174+
/// }
175+
///
176+
/// impl_tag! {
177+
/// // The type for which the `Tag` will be implemented
178+
/// impl Tag for SomeTag;
179+
/// // You need to specify all possible tag values:
180+
/// SomeTag::A, // 0
181+
/// SomeTag::B, // 1
182+
/// // For variants with fields, you need to specify the fields:
183+
/// SomeTag::X { v: true }, // 2
184+
/// SomeTag::X { v: false }, // 3
185+
/// // For tuple variants use named syntax:
186+
/// SomeTag::Y { 0: true, 1: true }, // 4
187+
/// SomeTag::Y { 0: false, 1: true }, // 5
188+
/// SomeTag::Y { 0: true, 1: false }, // 6
189+
/// SomeTag::Y { 0: false, 1: false }, // 7
190+
/// }
191+
///
192+
/// // Tag values are assigned in order:
193+
/// assert_eq!(SomeTag::A.into_usize(), 0);
194+
/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
195+
/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
196+
///
197+
/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
198+
/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
199+
/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
200+
/// ```
201+
///
202+
/// Structs are supported:
203+
///
204+
/// ```
205+
/// #![feature(macro_metavar_expr)]
206+
/// # use rustc_data_structures::impl_tag;
207+
/// #[derive(Copy, Clone)]
208+
/// struct Flags { a: bool, b: bool }
209+
///
210+
/// impl_tag! {
211+
/// impl Tag for Flags;
212+
/// Flags { a: true, b: true },
213+
/// Flags { a: false, b: true },
214+
/// Flags { a: true, b: false },
215+
/// Flags { a: false, b: false },
216+
/// }
217+
/// ```
218+
///
219+
/// Not specifying all values results in a compile error:
220+
///
221+
/// ```compile_fail,E0004
222+
/// #![feature(macro_metavar_expr)]
223+
/// # use rustc_data_structures::impl_tag;
224+
/// #[derive(Copy, Clone)]
225+
/// enum E {
226+
/// A,
227+
/// B,
228+
/// }
229+
///
230+
/// impl_tag! {
231+
/// impl Tag for E;
232+
/// E::A,
233+
/// }
234+
/// ```
235+
#[cfg(not(bootstrap))]
236+
#[macro_export]
237+
macro_rules! impl_tag {
238+
(
239+
impl Tag for $Self:ty;
240+
$(
241+
$($path:ident)::* $( { $( $fields:tt )* })?,
242+
)*
243+
) => {
244+
// Safety:
245+
// `bits_for_tags` is called on the same `${index()}`-es as
246+
// `into_usize` returns, thus `BITS` constant is correct.
247+
unsafe impl $crate::tagged_ptr::Tag for $Self {
248+
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
249+
$(
250+
${index()},
251+
$( ${ignore($path)} )*
252+
)*
253+
]);
254+
255+
#[inline]
256+
fn into_usize(self) -> usize {
257+
// This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
258+
// (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
259+
#[forbid(unreachable_patterns)]
260+
match self {
261+
// `match` is doing heavy lifting here, by requiring exhaustiveness
262+
$(
263+
$($path)::* $( { $( $fields )* } )? => ${index()},
264+
)*
265+
}
266+
}
267+
268+
#[inline]
269+
unsafe fn from_usize(tag: usize) -> Self {
270+
match tag {
271+
$(
272+
${index()} => $($path)::* $( { $( $fields )* } )?,
273+
)*
274+
275+
// Safety:
276+
// `into_usize` only returns `${index()}` of the same
277+
// repetition as we are filtering above, thus if this is
278+
// reached, the safety contract of this function was
279+
// already breached.
280+
_ => unsafe {
281+
debug_assert!(
282+
false,
283+
"invalid tag: {tag}\
284+
(this is a bug in the caller of `from_usize`)"
285+
);
286+
std::hint::unreachable_unchecked()
287+
},
288+
}
289+
}
290+
291+
}
292+
};
293+
}
294+
295+
143296
#[cfg(test)]
144297
mod tests;

0 commit comments

Comments
 (0)