From 339bbebbc1e66f836901e2ee9d3b9c1d2a07a21e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 9 Feb 2022 17:24:51 -0500 Subject: [PATCH 1/4] Convert `newtype_index` to a proc macro The `macro_rules!` implementation was becomng excessively complicated, and difficult to modify. The new proc macro implementation should make it much easier to add new features (e.g. skipping certain `#[derive]`s) --- compiler/rustc_index/src/lib.rs | 2 + compiler/rustc_index/src/vec.rs | 455 --------------------------- compiler/rustc_macros/src/lib.rs | 23 ++ compiler/rustc_macros/src/newtype.rs | 324 +++++++++++++++++++ 4 files changed, 349 insertions(+), 455 deletions(-) create mode 100644 compiler/rustc_macros/src/newtype.rs diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 0cfb7bd1106..33c3c536f11 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -12,6 +12,8 @@ pub mod interval; pub mod vec; +pub use rustc_macros::newtype_index; + /// Type size assertion. The first argument is a type and the second argument is its expected size. #[macro_export] macro_rules! static_assert_size { diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 8b61530577d..4656994ac08 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -49,461 +49,6 @@ fn index(self) -> usize { } } -/// Creates a struct type `S` that can be used as an index with -/// `IndexVec` and so on. -/// -/// There are two ways of interacting with these indices: -/// -/// - The `From` impls are the preferred way. So you can do -/// `S::from(v)` with a `usize` or `u32`. And you can convert back -/// to an integer with `u32::from(s)`. -/// -/// - Alternatively, you can use the methods `S::new(v)` and `s.index()` -/// to create/return a value. -/// -/// Internally, the index uses a u32, so the index must not exceed -/// `u32::MAX`. You can also customize things like the `Debug` impl, -/// what traits are derived, and so forth via the macro. -#[macro_export] -#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)] -macro_rules! newtype_index { - // ---- public rules ---- - - // Use default constants - ($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => ( - $crate::newtype_index!( - // Leave out derives marker so we can use its absence to ensure it comes first - @attrs [$(#[$attrs])*] - @type [$name] - // shave off 256 indices at the end to allow space for packing these indices into enums - @max [0xFFFF_FF00] - @vis [$v] - @debug_format ["{}"]); - ); - - // Define any constants - ($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => ( - $crate::newtype_index!( - // Leave out derives marker so we can use its absence to ensure it comes first - @attrs [$(#[$attrs])*] - @type [$name] - // shave off 256 indices at the end to allow space for packing these indices into enums - @max [0xFFFF_FF00] - @vis [$v] - @debug_format ["{}"] - $($tokens)+); - ); - - // ---- private rules ---- - - // Base case, user-defined constants (if any) have already been defined - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt]) => ( - $(#[$attrs])* - #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)] - #[rustc_layout_scalar_valid_range_end($max)] - $v struct $type { - private: u32 - } - - impl Clone for $type { - #[inline] - fn clone(&self) -> Self { - *self - } - } - - impl $type { - /// Maximum value the index can take, as a `u32`. - $v const MAX_AS_U32: u32 = $max; - - /// Maximum value the index can take. - $v const MAX: Self = Self::from_u32($max); - - /// Creates a new index from a given `usize`. - /// - /// # Panics - /// - /// Will panic if `value` exceeds `MAX`. - #[inline] - $v const fn from_usize(value: usize) -> Self { - assert!(value <= ($max as usize)); - // SAFETY: We just checked that `value <= max`. - unsafe { - Self::from_u32_unchecked(value as u32) - } - } - - /// Creates a new index from a given `u32`. - /// - /// # Panics - /// - /// Will panic if `value` exceeds `MAX`. - #[inline] - $v const fn from_u32(value: u32) -> Self { - assert!(value <= $max); - // SAFETY: We just checked that `value <= max`. - unsafe { - Self::from_u32_unchecked(value) - } - } - - /// Creates a new index from a given `u32`. - /// - /// # Safety - /// - /// The provided value must be less than or equal to the maximum value for the newtype. - /// Providing a value outside this range is undefined due to layout restrictions. - /// - /// Prefer using `from_u32`. - #[inline] - $v const unsafe fn from_u32_unchecked(value: u32) -> Self { - Self { private: value } - } - - /// Extracts the value of this index as a `usize`. - #[inline] - $v const fn index(self) -> usize { - self.as_usize() - } - - /// Extracts the value of this index as a `u32`. - #[inline] - $v const fn as_u32(self) -> u32 { - self.private - } - - /// Extracts the value of this index as a `usize`. - #[inline] - $v const fn as_usize(self) -> usize { - self.as_u32() as usize - } - } - - impl std::ops::Add for $type { - type Output = Self; - - fn add(self, other: usize) -> Self { - Self::from_usize(self.index() + other) - } - } - - impl $crate::vec::Idx for $type { - #[inline] - fn new(value: usize) -> Self { - Self::from_usize(value) - } - - #[inline] - fn index(self) -> usize { - self.as_usize() - } - } - - impl ::std::iter::Step for $type { - #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { - ::steps_between( - &Self::index(*start), - &Self::index(*end), - ) - } - - #[inline] - fn forward_checked(start: Self, u: usize) -> Option { - Self::index(start).checked_add(u).map(Self::from_usize) - } - - #[inline] - fn backward_checked(start: Self, u: usize) -> Option { - Self::index(start).checked_sub(u).map(Self::from_usize) - } - } - - // Safety: The implementation of `Step` upholds all invariants. - unsafe impl ::std::iter::TrustedStep for $type {} - - impl From<$type> for u32 { - #[inline] - fn from(v: $type) -> u32 { - v.as_u32() - } - } - - impl From<$type> for usize { - #[inline] - fn from(v: $type) -> usize { - v.as_usize() - } - } - - impl From for $type { - #[inline] - fn from(value: usize) -> Self { - Self::from_usize(value) - } - } - - impl From for $type { - #[inline] - fn from(value: u32) -> Self { - Self::from_u32(value) - } - } - - $crate::newtype_index!( - @handle_debug - @derives [$($derives,)*] - @type [$type] - @debug_format [$debug_format]); - ); - - // base case for handle_debug where format is custom. No Debug implementation is emitted. - (@handle_debug - @derives [$($_derives:ident,)*] - @type [$type:ident] - @debug_format [custom]) => (); - - // base case for handle_debug, no debug overrides found, so use default - (@handle_debug - @derives [] - @type [$type:ident] - @debug_format [$debug_format:tt]) => ( - impl ::std::fmt::Debug for $type { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(fmt, $debug_format, self.as_u32()) - } - } - ); - - // Debug is requested for derive, don't generate any Debug implementation. - (@handle_debug - @derives [Debug, $($derives:ident,)*] - @type [$type:ident] - @debug_format [$debug_format:tt]) => (); - - // It's not Debug, so just pop it off the front of the derives stack and check the rest. - (@handle_debug - @derives [$_derive:ident, $($derives:ident,)*] - @type [$type:ident] - @debug_format [$debug_format:tt]) => ( - $crate::newtype_index!( - @handle_debug - @derives [$($derives,)*] - @type [$type] - @debug_format [$debug_format]); - ); - - // Append comma to end of derives list if it's missing - (@attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - derive [$($derives:ident),*] - $($tokens:tt)*) => ( - $crate::newtype_index!( - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - derive [$($derives,)*] - $($tokens)*); - ); - - // By not including the @derives marker in this list nor in the default args, we can force it - // to come first if it exists. When encodable is custom, just use the derives list as-is. - (@attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - derive [$($derives:ident,)+] - ENCODABLE = custom - $($tokens:tt)*) => ( - $crate::newtype_index!( - @attrs [$(#[$attrs])*] - @derives [$($derives,)+] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - ); - - // By not including the @derives marker in this list nor in the default args, we can force it - // to come first if it exists. When encodable isn't custom, add serialization traits by default. - (@attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - derive [$($derives:ident,)+] - $($tokens:tt)*) => ( - $crate::newtype_index!( - @derives [$($derives,)+] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - $crate::newtype_index!(@serializable $type); - ); - - // The case where no derives are added, but encodable is overridden. Don't - // derive serialization traits - (@attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - ENCODABLE = custom - $($tokens:tt)*) => ( - $crate::newtype_index!( - @derives [] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - ); - - // The case where no derives are added, add serialization derives by default - (@attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - $($tokens:tt)*) => ( - $crate::newtype_index!( - @derives [] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - $crate::newtype_index!(@serializable $type); - ); - - (@serializable $type:ident) => ( - impl ::rustc_serialize::Decodable for $type { - fn decode(d: &mut D) -> Self { - Self::from_u32(d.read_u32()) - } - } - impl ::rustc_serialize::Encodable for $type { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { - e.emit_u32(self.private) - } - } - ); - - // Rewrite final without comma to one that includes comma - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - $name:ident = $constant:expr) => ( - $crate::newtype_index!( - @derives [$($derives,)*] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $name = $constant,); - ); - - // Rewrite final const without comma to one that includes comma - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - $(#[doc = $doc:expr])* - const $name:ident = $constant:expr) => ( - $crate::newtype_index!( - @derives [$($derives,)*] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $(#[doc = $doc])* const $name = $constant,); - ); - - // Replace existing default for max - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$_max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - MAX = $max:expr, - $($tokens:tt)*) => ( - $crate::newtype_index!( - @derives [$($derives,)*] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - ); - - // Replace existing default for debug_format - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$_debug_format:tt] - DEBUG_FORMAT = $debug_format:tt, - $($tokens:tt)*) => ( - $crate::newtype_index!( - @derives [$($derives,)*] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - ); - - // Assign a user-defined constant - (@derives [$($derives:ident,)*] - @attrs [$(#[$attrs:meta])*] - @type [$type:ident] - @max [$max:expr] - @vis [$v:vis] - @debug_format [$debug_format:tt] - $(#[doc = $doc:expr])* - const $name:ident = $constant:expr, - $($tokens:tt)*) => ( - $(#[doc = $doc])* - $v const $name: $type = $type::from_u32($constant); - $crate::newtype_index!( - @derives [$($derives,)*] - @attrs [$(#[$attrs])*] - @type [$type] - @max [$max] - @vis [$v] - @debug_format [$debug_format] - $($tokens)*); - ); -} - #[derive(Clone, PartialEq, Eq, Hash)] pub struct IndexVec { pub raw: Vec, diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 152ae159aed..03e139755ba 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,4 +1,5 @@ #![feature(proc_macro_diagnostic)] +#![feature(allow_internal_unstable)] #![allow(rustc::default_hash_types)] #![recursion_limit = "128"] @@ -8,6 +9,7 @@ mod hash_stable; mod lift; +mod newtype; mod query; mod serialize; mod session_diagnostic; @@ -24,6 +26,27 @@ pub fn symbols(input: TokenStream) -> TokenStream { symbols::symbols(input.into()).into() } +/// Creates a struct type `S` that can be used as an index with +/// `IndexVec` and so on. +/// +/// There are two ways of interacting with these indices: +/// +/// - The `From` impls are the preferred way. So you can do +/// `S::from(v)` with a `usize` or `u32`. And you can convert back +/// to an integer with `u32::from(s)`. +/// +/// - Alternatively, you can use the methods `S::new(v)` and `s.index()` +/// to create/return a value. +/// +/// Internally, the index uses a u32, so the index must not exceed +/// `u32::MAX`. You can also customize things like the `Debug` impl, +/// what traits are derived, and so forth via the macro. +#[proc_macro] +#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)] +pub fn newtype_index(input: TokenStream) -> TokenStream { + newtype::newtype(input).into() +} + decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs new file mode 100644 index 00000000000..b59ec34ba7b --- /dev/null +++ b/compiler/rustc_macros/src/newtype.rs @@ -0,0 +1,324 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::parse::*; +use syn::punctuated::Punctuated; +use syn::*; + +mod kw { + syn::custom_keyword!(derive); + syn::custom_keyword!(DEBUG_FORMAT); + syn::custom_keyword!(MAX); + syn::custom_keyword!(ENCODABLE); + syn::custom_keyword!(custom); +} + +#[derive(Debug)] +enum DebugFormat { + // The user will provide a custom `Debug` impl, so we shouldn't generate + // one + Custom, + // Use the specified format string in the generated `Debug` impl + // By default, this is "{}" + Format(String), +} + +// We parse the input and emit the output in a single step. +// This field stores the final macro output +struct Newtype(TokenStream); + +impl Parse for Newtype { + fn parse(input: ParseStream<'_>) -> Result { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + input.parse::()?; + let name: Ident = input.parse()?; + + let body; + braced!(body in input); + + // Any additional `#[derive]` macro paths to apply + let mut derive_paths: Option> = None; + let mut debug_format: Option = None; + let mut max = None; + let mut consts = Vec::new(); + let mut encodable = true; + + // Parse an optional trailing comma + let try_comma = || -> Result<()> { + if body.lookahead1().peek(Token![,]) { + body.parse::()?; + } + Ok(()) + }; + + if body.lookahead1().peek(Token![..]) { + body.parse::()?; + } else { + loop { + if body.lookahead1().peek(kw::derive) { + body.parse::()?; + let derives; + bracketed!(derives in body); + let derives: Punctuated = + derives.parse_terminated(Path::parse)?; + try_comma()?; + if let Some(old) = derive_paths.replace(derives.into_iter().collect()) { + panic!("Specified multiple derives: {:?}", old); + } + continue; + } + if body.lookahead1().peek(kw::DEBUG_FORMAT) { + body.parse::()?; + body.parse::()?; + if body.lookahead1().peek(kw::custom) { + body.parse::()?; + if let Some(old) = debug_format.replace(DebugFormat::Custom) { + panic!("Specified multiple debug format options: {:?}", old); + } + } else { + let format_str: LitStr = body.parse()?; + if let Some(old) = + debug_format.replace(DebugFormat::Format(format_str.value())) + { + panic!("Specified multiple debug format options: {:?}", old); + } + } + try_comma()?; + continue; + } + if body.lookahead1().peek(kw::MAX) { + body.parse::()?; + body.parse::()?; + let val: Lit = body.parse()?; + try_comma()?; + if let Some(old) = max.replace(val) { + panic!("Specified multiple MAX: {:?}", old); + } + continue; + } + if body.lookahead1().peek(kw::ENCODABLE) { + body.parse::()?; + body.parse::()?; + body.parse::()?; + try_comma()?; + encodable = false; + continue; + } + + // We've parsed everything that the user provided, so we're done + if body.is_empty() { + break; + } + + // Otherwise, we are parsng a user-defined constant + let const_attrs = body.call(Attribute::parse_outer)?; + body.parse::()?; + let const_name: Ident = body.parse()?; + body.parse::()?; + let const_val: Expr = body.parse()?; + try_comma()?; + consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); }); + } + } + + let derive_paths = derive_paths.unwrap_or_else(Vec::new); + let debug_format = debug_format.unwrap_or(DebugFormat::Format("{}".to_string())); + // shave off 256 indices at the end to allow space for packing these indices into enums + let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site()))); + + let encodable_impls = if encodable { + quote! { + impl ::rustc_serialize::Decodable for #name { + fn decode(d: &mut D) -> Self { + Self::from_u32(d.read_u32()) + } + } + impl ::rustc_serialize::Encodable for #name { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_u32(self.private) + } + } + } + } else { + quote! {} + }; + + let debug_impl = match debug_format { + DebugFormat::Custom => quote! {}, + DebugFormat::Format(format) => { + quote! { + impl ::std::fmt::Debug for #name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(fmt, #format, self.as_u32()) + } + } + } + } + }; + + Ok(Self(quote! { + #(#attrs)* + #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, #(#derive_paths),*)] + #[rustc_layout_scalar_valid_range_end(#max)] + #vis struct #name { + private: u32, + } + + #(#consts)* + + impl Clone for #name { + #[inline] + fn clone(&self) -> Self { + *self + } + } + + impl #name { + /// Maximum value the index can take, as a `u32`. + #vis const MAX_AS_U32: u32 = #max; + + /// Maximum value the index can take. + #vis const MAX: Self = Self::from_u32(#max); + + /// Creates a new index from a given `usize`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. + #[inline] + #vis const fn from_usize(value: usize) -> Self { + assert!(value <= (#max as usize)); + // SAFETY: We just checked that `value <= max`. + unsafe { + Self::from_u32_unchecked(value as u32) + } + } + + /// Creates a new index from a given `u32`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. + #[inline] + #vis const fn from_u32(value: u32) -> Self { + assert!(value <= #max); + // SAFETY: We just checked that `value <= max`. + unsafe { + Self::from_u32_unchecked(value) + } + } + + /// Creates a new index from a given `u32`. + /// + /// # Safety + /// + /// The provided value must be less than or equal to the maximum value for the newtype. + /// Providing a value outside this range is undefined due to layout restrictions. + /// + /// Prefer using `from_u32`. + #[inline] + #vis const unsafe fn from_u32_unchecked(value: u32) -> Self { + Self { private: value } + } + + /// Extracts the value of this index as a `usize`. + #[inline] + #vis const fn index(self) -> usize { + self.as_usize() + } + + /// Extracts the value of this index as a `u32`. + #[inline] + #vis const fn as_u32(self) -> u32 { + self.private + } + + /// Extracts the value of this index as a `usize`. + #[inline] + #vis const fn as_usize(self) -> usize { + self.as_u32() as usize + } + } + + impl std::ops::Add for #name { + type Output = Self; + + fn add(self, other: usize) -> Self { + Self::from_usize(self.index() + other) + } + } + + impl rustc_index::vec::Idx for #name { + #[inline] + fn new(value: usize) -> Self { + Self::from_usize(value) + } + + #[inline] + fn index(self) -> usize { + self.as_usize() + } + } + + impl ::std::iter::Step for #name { + #[inline] + fn steps_between(start: &Self, end: &Self) -> Option { + ::steps_between( + &Self::index(*start), + &Self::index(*end), + ) + } + + #[inline] + fn forward_checked(start: Self, u: usize) -> Option { + Self::index(start).checked_add(u).map(Self::from_usize) + } + + #[inline] + fn backward_checked(start: Self, u: usize) -> Option { + Self::index(start).checked_sub(u).map(Self::from_usize) + } + } + + // Safety: The implementation of `Step` upholds all invariants. + unsafe impl ::std::iter::TrustedStep for #name {} + + impl From<#name> for u32 { + #[inline] + fn from(v: #name) -> u32 { + v.as_u32() + } + } + + impl From<#name> for usize { + #[inline] + fn from(v: #name) -> usize { + v.as_usize() + } + } + + impl From for #name { + #[inline] + fn from(value: usize) -> Self { + Self::from_usize(value) + } + } + + impl From for #name { + #[inline] + fn from(value: u32) -> Self { + Self::from_u32(value) + } + } + + #encodable_impls + #debug_impl + + })) + } +} + +pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as Newtype); + input.0.into() +} From e686aee48eed69c0dc4f6ed1bd31e0df352a7008 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 18 Feb 2022 16:16:02 -0500 Subject: [PATCH 2/4] Fix test --- compiler/rustc_index/src/vec/tests.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs index 15c43c72c7b..915d2e8bcb3 100644 --- a/compiler/rustc_index/src/vec/tests.rs +++ b/compiler/rustc_index/src/vec/tests.rs @@ -1,5 +1,9 @@ #![allow(dead_code)] -newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA }); + +// Allows the macro invocation below to work +use crate as rustc_index; + +rustc_macros::newtype_index!(struct MyIdx { MAX = 0xFFFF_FFFA }); #[test] fn index_size_is_optimized() { From 01efe6d5c25b73a311ce03ec80744628f1ec8978 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 18 Feb 2022 19:14:51 -0500 Subject: [PATCH 3/4] Address review comments --- compiler/rustc_macros/src/newtype.rs | 34 ++++++++-------------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs index b59ec34ba7b..f284e5cdd5c 100644 --- a/compiler/rustc_macros/src/newtype.rs +++ b/compiler/rustc_macros/src/newtype.rs @@ -37,7 +37,7 @@ fn parse(input: ParseStream<'_>) -> Result { braced!(body in input); // Any additional `#[derive]` macro paths to apply - let mut derive_paths: Option> = None; + let mut derive_paths: Vec = Vec::new(); let mut debug_format: Option = None; let mut max = None; let mut consts = Vec::new(); @@ -62,28 +62,23 @@ fn parse(input: ParseStream<'_>) -> Result { let derives: Punctuated = derives.parse_terminated(Path::parse)?; try_comma()?; - if let Some(old) = derive_paths.replace(derives.into_iter().collect()) { - panic!("Specified multiple derives: {:?}", old); - } + derive_paths.extend(derives); continue; } if body.lookahead1().peek(kw::DEBUG_FORMAT) { body.parse::()?; body.parse::()?; - if body.lookahead1().peek(kw::custom) { + let new_debug_format = if body.lookahead1().peek(kw::custom) { body.parse::()?; - if let Some(old) = debug_format.replace(DebugFormat::Custom) { - panic!("Specified multiple debug format options: {:?}", old); - } + DebugFormat::Custom } else { let format_str: LitStr = body.parse()?; - if let Some(old) = - debug_format.replace(DebugFormat::Format(format_str.value())) - { - panic!("Specified multiple debug format options: {:?}", old); - } - } + DebugFormat::Format(format_str.value()) + }; try_comma()?; + if let Some(old) = debug_format.replace(new_debug_format) { + panic!("Specified multiple debug format options: {:?}", old); + } continue; } if body.lookahead1().peek(kw::MAX) { @@ -121,7 +116,6 @@ fn parse(input: ParseStream<'_>) -> Result { } } - let derive_paths = derive_paths.unwrap_or_else(Vec::new); let debug_format = debug_format.unwrap_or(DebugFormat::Format("{}".to_string())); // shave off 256 indices at the end to allow space for packing these indices into enums let max = max.unwrap_or_else(|| Lit::Int(LitInt::new("0xFFFF_FF00", Span::call_site()))); @@ -158,7 +152,7 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { Ok(Self(quote! { #(#attrs)* - #[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, #(#derive_paths),*)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, #(#derive_paths),*)] #[rustc_layout_scalar_valid_range_end(#max)] #vis struct #name { private: u32, @@ -166,13 +160,6 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { #(#consts)* - impl Clone for #name { - #[inline] - fn clone(&self) -> Self { - *self - } - } - impl #name { /// Maximum value the index can take, as a `u32`. #vis const MAX_AS_U32: u32 = #max; @@ -313,7 +300,6 @@ fn from(value: u32) -> Self { #encodable_impls #debug_impl - })) } } From 7b7b0f148c0e76136beb3c24d392f25bb4044612 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Feb 2022 17:16:36 -0500 Subject: [PATCH 4/4] Fix intra-doc link issues exposed by new macro These links never worked, but the lint was suppressed due to the fact that the span was pointing into the macro. With the new macro implementation, the span now points directly to the doc comment in the macro invocation, so it's no longer suppressed. --- compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_mir_transform/src/coverage/graph.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 52e143916ce..9a36230516c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1847,6 +1847,7 @@ pub fn is_field_to(&self, f: Field) -> bool { /// rustc can identify that a field projection refers to either two different regions of memory /// or the same one between the base and the 'projection element'. /// Read more about projections in the [rustc-dev-guide][mir-datatypes] + /// /// [wrapper]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html#newtype /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg /// [mir-datatypes]: https://rustc-dev-guide.rust-lang.org/mir/index.html#mir-data-types diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 57862b6628d..55f7e70db8f 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -281,7 +281,7 @@ fn predecessors(&self, node: Self::Node) ->