diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 426d2c4034b..004017ec5f3 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -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)] diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs index d263bed9581..0b0c152cc4d 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs @@ -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 ) - #[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, diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs index cd19b30ff53..62c926153e1 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs @@ -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); } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 76a8367b2c4..e9172e767e0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -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)] diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d13c71b78e4..88de43478b8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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> {