Skip to content

Commit 4154061

Browse files
committed
Fix CI
1 parent b01220c commit 4154061

File tree

1 file changed

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

1 file changed

+144
-0
lines changed

compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs

+144
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
(
@@ -140,5 +141,148 @@ macro_rules! impl_tag {
140141
};
141142
}
142143

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

0 commit comments

Comments
 (0)