Switch impl_tag! from explicit tags to ${index()}

This commit is contained in:
Maybe Waffle 2023-04-24 16:48:37 +00:00
parent ad8c7b6705
commit 2b8d27b402
5 changed files with 57 additions and 51 deletions

View File

@ -31,6 +31,7 @@
#![feature(unwrap_infallible)]
#![feature(strict_provenance)]
#![feature(ptr_alignment_type)]
#![feature(macro_metavar_expr)]
#![allow(rustc::default_hash_types)]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]

View File

@ -11,6 +11,7 @@
/// Basic usage:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
///
/// #[derive(Copy, Clone, PartialEq, Debug)]
@ -24,19 +25,20 @@
/// impl_tag! {
/// // The type for which the `Tag` will be implemented
/// impl Tag for SomeTag;
/// // You need to specify the `{value_of_the_type} <=> {tag}` relationship
/// SomeTag::A <=> 0,
/// SomeTag::B <=> 1,
/// // You need to specify all possible tag values:
/// SomeTag::A, // 0
/// SomeTag::B, // 1
/// // For variants with fields, you need to specify the fields:
/// SomeTag::X { v: true } <=> 2,
/// SomeTag::X { v: false } <=> 3,
/// SomeTag::X { v: true }, // 2
/// SomeTag::X { v: false }, // 3
/// // For tuple variants use named syntax:
/// SomeTag::Y { 0: true, 1: true } <=> 4,
/// SomeTag::Y { 0: false, 1: true } <=> 5,
/// SomeTag::Y { 0: true, 1: false } <=> 6,
/// SomeTag::Y { 0: false, 1: false } <=> 7,
/// SomeTag::Y { 0: true, 1: true }, // 4
/// SomeTag::Y { 0: false, 1: true }, // 5
/// SomeTag::Y { 0: true, 1: false }, // 6
/// SomeTag::Y { 0: false, 1: false }, // 7
/// }
///
/// // Tag values are assigned in order:
/// assert_eq!(SomeTag::A.into_usize(), 0);
/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
@ -49,22 +51,24 @@
/// Structs are supported:
///
/// ```
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// struct Flags { a: bool, b: bool }
///
/// impl_tag! {
/// impl Tag for Flags;
/// Flags { a: true, b: true } <=> 3,
/// Flags { a: false, b: true } <=> 2,
/// Flags { a: true, b: false } <=> 1,
/// Flags { a: false, b: false } <=> 0,
/// Flags { a: true, b: true },
/// Flags { a: false, b: true },
/// Flags { a: true, b: false },
/// Flags { a: false, b: false },
/// }
/// ```
///
/// Not specifying all values results in a compile error:
///
/// ```compile_fail,E0004
/// #![feature(macro_metavar_expr)]
/// # use rustc_data_structures::impl_tag;
/// #[derive(Copy, Clone)]
/// enum E {
@ -74,7 +78,7 @@
///
/// impl_tag! {
/// impl Tag for E;
/// E::A <=> 0,
/// E::A,
/// }
/// ```
#[macro_export]
@ -82,16 +86,18 @@ macro_rules! impl_tag {
(
impl Tag for $Self:ty;
$(
$($path:ident)::* $( { $( $fields:tt )* })? <=> $tag:literal,
$($path:ident)::* $( { $( $fields:tt )* })?,
)*
) => {
// Safety:
// `into_usize` only returns one of `$tag`s,
// `bits_for_tags` is called on all `$tag`s,
// thus `BITS` constant is correct.
// `bits_for_tags` is called on the same `${index()}`-es as
// `into_usize` returns, thus `BITS` constant is correct.
unsafe impl $crate::tagged_ptr::Tag for $Self {
const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
$( $tag, )*
$(
${index()},
$( ${ignore(path)} )*
)*
]);
fn into_usize(self) -> usize {
@ -101,25 +107,22 @@ fn into_usize(self) -> usize {
match self {
// `match` is doing heavy lifting here, by requiring exhaustiveness
$(
$($path)::* $( { $( $fields )* } )? => $tag,
$($path)::* $( { $( $fields )* } )? => ${index()},
)*
}
}
unsafe fn from_usize(tag: usize) -> Self {
// Similarly to the above, this forbids repeating tags
// (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
#[forbid(unreachable_patterns)]
match tag {
$(
$tag => $($path)::* $( { $( $fields )* } )?,
${index()} => $($path)::* $( { $( $fields )* } )?,
)*
// Safety:
// `into_usize` only returns one of `$tag`s,
// all `$tag`s are filtered up above,
// thus if this is reached, the safety contract of this
// function was already breached.
// `into_usize` only returns `${index()}` of the same
// repetition as we are filtering above, thus if this is
// reached, the safety contract of this function was
// already breached.
_ => unsafe {
debug_assert!(
false,

View File

@ -4,30 +4,31 @@ fn bits_constant() {
#[derive(Copy, Clone)]
struct Unit;
impl_tag! { impl Tag for Unit; Unit <=> 0, }
impl_tag! { impl Tag for Unit; Unit, }
assert_eq!(Unit::BITS, 0);
#[derive(Copy, Clone)]
struct Unit1;
impl_tag! { impl Tag for Unit1; Unit1 <=> 1, }
assert_eq!(Unit1::BITS, 1);
#[derive(Copy, Clone)]
struct Unit2;
impl_tag! { impl Tag for Unit2; Unit2 <=> 0b10, }
assert_eq!(Unit2::BITS, 2);
#[derive(Copy, Clone)]
struct Unit3;
impl_tag! { impl Tag for Unit3; Unit3 <=> 0b100, }
assert_eq!(Unit3::BITS, 3);
#[derive(Copy, Clone)]
enum Enum {
enum Enum3 {
A,
B,
C,
}
impl_tag! { impl Tag for Enum; Enum::A <=> 0b1, Enum::B <=> 0b1000, Enum::C <=> 0b10, }
assert_eq!(Enum::BITS, 4);
impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, }
assert_eq!(Enum3::BITS, 2);
#[derive(Copy, Clone)]
struct Eight(bool, bool, bool);
impl_tag! {
impl Tag for Eight;
Eight { 0: true, 1: true, 2: true },
Eight { 0: true, 1: true, 2: false },
Eight { 0: true, 1: false, 2: true },
Eight { 0: true, 1: false, 2: false },
Eight { 0: false, 1: true, 2: true },
Eight { 0: false, 1: true, 2: false },
Eight { 0: false, 1: false, 2: true },
Eight { 0: false, 1: false, 2: false },
}
assert_eq!(Eight::BITS, 3);
}

View File

@ -60,6 +60,7 @@
#![feature(const_option)]
#![feature(trait_alias)]
#![feature(ptr_alignment_type)]
#![feature(macro_metavar_expr)]
#![recursion_limit = "512"]
#![allow(rustc::potential_query_instability)]

View File

@ -1628,10 +1628,10 @@ struct ParamTag {
impl_tag! {
impl Tag for ParamTag;
ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } <=> 0,
ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } <=> 1,
ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } <=> 2,
ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const } <=> 3,
ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const },
}
impl<'tcx> fmt::Debug for ParamEnv<'tcx> {