From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_macros/src/current_version.rs | 37 +-- .../rustc_macros/src/diagnostics/diagnostic.rs | 27 +- .../src/diagnostics/diagnostic_builder.rs | 19 +- .../rustc_macros/src/diagnostics/subdiagnostic.rs | 2 +- compiler/rustc_macros/src/diagnostics/utils.rs | 6 +- compiler/rustc_macros/src/hash_stable.rs | 140 +++++---- compiler/rustc_macros/src/lib.rs | 32 +-- compiler/rustc_macros/src/lift.rs | 2 +- compiler/rustc_macros/src/newtype.rs | 312 --------------------- compiler/rustc_macros/src/symbols.rs | 17 +- 10 files changed, 133 insertions(+), 461 deletions(-) delete mode 100644 compiler/rustc_macros/src/newtype.rs (limited to 'compiler/rustc_macros') diff --git a/compiler/rustc_macros/src/current_version.rs b/compiler/rustc_macros/src/current_version.rs index 5e3b91c17..42ca60a6d 100644 --- a/compiler/rustc_macros/src/current_version.rs +++ b/compiler/rustc_macros/src/current_version.rs @@ -1,37 +1,16 @@ use proc_macro::TokenStream; use proc_macro2::Span; use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::{parenthesized, parse_macro_input, LitStr, Token}; -pub struct Input { - variable: LitStr, -} - -mod kw { - syn::custom_keyword!(env); -} - -impl Parse for Input { - // Input syntax is `env!("CFG_RELEASE")` to facilitate grepping. - fn parse(input: ParseStream<'_>) -> syn::Result { - let paren; - input.parse::()?; - input.parse::()?; - parenthesized!(paren in input); - let variable: LitStr = paren.parse()?; - Ok(Input { variable }) - } -} - -pub(crate) fn current_version(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as Input); - - TokenStream::from(match RustcVersion::parse_env_var(&input.variable) { +pub(crate) fn current_version(_input: TokenStream) -> TokenStream { + let env_var = "CFG_RELEASE"; + TokenStream::from(match RustcVersion::parse_cfg_release(env_var) { Ok(RustcVersion { major, minor, patch }) => quote!( + // The produced literal has type `rustc_session::RustcVersion`. Self { major: #major, minor: #minor, patch: #patch } ), - Err(err) => syn::Error::new(Span::call_site(), err).into_compile_error(), + Err(err) => syn::Error::new(Span::call_site(), format!("{env_var} env var: {err}")) + .into_compile_error(), }) } @@ -42,8 +21,8 @@ struct RustcVersion { } impl RustcVersion { - fn parse_env_var(env_var: &LitStr) -> Result> { - let value = proc_macro::tracked_env::var(env_var.value())?; + fn parse_cfg_release(env_var: &str) -> Result> { + let value = proc_macro::tracked_env::var(env_var)?; Self::parse_str(&value) .ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into()) } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 1a8174bfd..5de0203fc 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -17,11 +17,11 @@ pub(crate) struct DiagnosticDerive<'a> { } impl<'a> DiagnosticDerive<'a> { - pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self { + pub(crate) fn new(diag: syn::Ident, dcx: syn::Ident, structure: Structure<'a>) -> Self { Self { builder: DiagnosticDeriveBuilder { diag, - kind: DiagnosticDeriveKind::Diagnostic { handler }, + kind: DiagnosticDeriveKind::Diagnostic { dcx }, }, structure, } @@ -36,7 +36,7 @@ impl<'a> DiagnosticDerive<'a> { let body = builder.body(variant); let diag = &builder.parent.diag; - let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else { + let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.parent.kind else { unreachable!() }; let init = match builder.slug.value_ref() { @@ -62,7 +62,7 @@ impl<'a> DiagnosticDerive<'a> { Some(slug) => { slugs.borrow_mut().push(slug.clone()); quote! { - let mut #diag = #handler.struct_diagnostic(crate::fluent_generated::#slug); + let mut #diag = #dcx.struct_diagnostic(crate::fluent_generated::#slug); } } }; @@ -77,11 +77,12 @@ impl<'a> DiagnosticDerive<'a> { } }); - let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() }; + let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.kind else { unreachable!() }; + // A lifetime of `'a` causes conflicts, but `_sess` is fine. let mut imp = structure.gen_impl(quote! { - gen impl<'__diagnostic_handler_sess, G> - rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G> + gen impl<'_sess, G> + rustc_errors::IntoDiagnostic<'_sess, G> for @Self where G: rustc_errors::EmissionGuarantee { @@ -89,8 +90,8 @@ impl<'a> DiagnosticDerive<'a> { #[track_caller] fn into_diagnostic( self, - #handler: &'__diagnostic_handler_sess rustc_errors::Handler - ) -> rustc_errors::DiagnosticBuilder<'__diagnostic_handler_sess, G> { + #dcx: &'_sess rustc_errors::DiagCtxt + ) -> rustc_errors::DiagnosticBuilder<'_sess, G> { use rustc_errors::IntoDiagnosticArg; #implementation } @@ -175,9 +176,9 @@ impl<'a> LintDiagnosticDerive<'a> { fn decorate_lint<'__b>( self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> - ) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> { + ) { use rustc_errors::IntoDiagnosticArg; - #implementation + #implementation; } fn msg(&self) -> rustc_errors::DiagnosticMessage { @@ -229,8 +230,8 @@ fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream { } } use std::sync::atomic::{AtomicUsize, Ordering}; - // We need to make sure that the same diagnostic slug can be used multiple times without causing an - // error, so just have a global counter here. + // We need to make sure that the same diagnostic slug can be used multiple times without + // causing an error, so just have a global counter here. static COUNTER: AtomicUsize = AtomicUsize::new(0); let slug = slug.get_ident().unwrap(); let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed)); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index e9a5cd9de..511654d99 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -19,7 +19,7 @@ use super::utils::SubdiagnosticVariant; /// What kind of diagnostic is being derived - a fatal/error/warning or a lint? #[derive(Clone, PartialEq, Eq)] pub(crate) enum DiagnosticDeriveKind { - Diagnostic { handler: syn::Ident }, + Diagnostic { dcx: syn::Ident }, LintDiagnostic, } @@ -53,6 +53,7 @@ pub(crate) struct DiagnosticDeriveVariantBuilder<'parent> { /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that /// has the actual diagnostic message. pub slug: SpannedOption, + /// Error codes are a optional part of the struct attribute - this is only set to detect /// multiple specifications. pub code: SpannedOption<()>, @@ -68,7 +69,7 @@ impl DiagnosticDeriveBuilder { /// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the /// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions /// or attributes on the type itself when input is an enum. - pub fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> TokenStream + pub(crate) fn each_variant<'s, F>(&mut self, structure: &mut Structure<'s>, f: F) -> TokenStream where F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream, { @@ -121,7 +122,7 @@ impl DiagnosticDeriveBuilder { impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `code` and similar functions based on the attributes on the type or /// variant. - pub fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { + pub(crate) fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let ast = variant.ast(); let attrs = &ast.attrs; let preamble = attrs.iter().map(|attr| { @@ -135,7 +136,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { /// Generates calls to `span_label` and similar functions based on the attributes on fields or /// calls to `set_arg` when no attributes are present. - pub fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { + pub(crate) fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let mut body = quote! {}; // Generate `set_arg` calls first.. for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) { @@ -347,11 +348,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { } (Meta::Path(_), "subdiagnostic") => { if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() { - let DiagnosticDeriveKind::Diagnostic { handler } = &self.parent.kind else { + let DiagnosticDeriveKind::Diagnostic { dcx } = &self.parent.kind else { // No eager translation for lints. return Ok(quote! { #diag.subdiagnostic(#binding); }); }; - return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); }); + return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); }); } else { return Ok(quote! { #diag.subdiagnostic(#binding); }); } @@ -375,15 +376,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(quote! {}); } - let handler = match &self.parent.kind { - DiagnosticDeriveKind::Diagnostic { handler } => handler, + let dcx = match &self.parent.kind { + DiagnosticDeriveKind::Diagnostic { dcx } => dcx, DiagnosticDeriveKind::LintDiagnostic => { throw_invalid_attr!(attr, |diag| { diag.help("eager subdiagnostics are not supported on lints") }) } }; - return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); }); + return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); }); } _ => (), } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 877271ff0..0f9e68cdc 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -478,7 +478,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } - pub fn into_tokens(&mut self) -> Result { + pub(crate) fn into_tokens(&mut self) -> Result { let kind_slugs = self.identify_kind()?; if kind_slugs.is_empty() { if self.is_enum { diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 125632921..2700f02e3 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -17,7 +17,7 @@ use synstructure::{BindingInfo, VariantInfo}; use super::error::invalid_attr; thread_local! { - pub static CODE_IDENT_COUNT: RefCell = RefCell::new(0); + pub(crate) static CODE_IDENT_COUNT: RefCell = RefCell::new(0); } /// Returns an ident of the form `__code_N` where `N` is incremented once with every call. @@ -208,7 +208,7 @@ impl<'ty> FieldInnerTy<'ty> { } } - pub fn span(&self) -> proc_macro2::Span { + pub(crate) fn span(&self) -> proc_macro2::Span { match self { FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(), } @@ -537,7 +537,7 @@ impl fmt::Display for SuggestionKind { } impl SuggestionKind { - pub fn to_suggestion_style(&self) -> TokenStream { + pub(crate) fn to_suggestion_style(&self) -> TokenStream { match self { SuggestionKind::Normal => { quote! { rustc_errors::SuggestionStyle::ShowCode } diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index 75a2f7009..a6396ba68 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -1,6 +1,6 @@ -use proc_macro2::{self, Ident}; +use proc_macro2::Ident; use quote::quote; -use syn::{self, parse_quote}; +use syn::parse_quote; struct Attributes { ignore: bool, @@ -38,41 +38,80 @@ fn parse_attributes(field: &syn::Field) -> Attributes { attrs } -pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - let generic: syn::GenericParam = parse_quote!(__CTX); - s.add_bounds(synstructure::AddBounds::Generics); - s.add_impl_generic(generic); - s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext }); - let body = s.each(|bi| { - let attrs = parse_attributes(bi.ast()); - if attrs.ignore { - quote! {} - } else if let Some(project) = attrs.project { - quote! { - (&#bi.#project).hash_stable(__hcx, __hasher); - } - } else { - quote! { - #bi.hash_stable(__hcx, __hasher); - } - } +pub(crate) fn hash_stable_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + hash_stable_derive_with_mode(s, HashStableMode::Normal) +} + +pub(crate) fn hash_stable_generic_derive( + s: synstructure::Structure<'_>, +) -> proc_macro2::TokenStream { + hash_stable_derive_with_mode(s, HashStableMode::Generic) +} + +pub(crate) fn hash_stable_no_context_derive( + s: synstructure::Structure<'_>, +) -> proc_macro2::TokenStream { + hash_stable_derive_with_mode(s, HashStableMode::NoContext) +} + +enum HashStableMode { + // Use the query-system aware stable hashing context. + Normal, + // Emit a generic implementation that uses a crate-local `StableHashingContext` + // trait, when the crate is upstream of `rustc_middle`. + Generic, + // Emit a hash-stable implementation that takes no context, + // and emits per-field where clauses for (almost-)perfect derives. + NoContext, +} + +fn hash_stable_derive_with_mode( + mut s: synstructure::Structure<'_>, + mode: HashStableMode, +) -> proc_macro2::TokenStream { + let generic: syn::GenericParam = match mode { + HashStableMode::Normal => parse_quote!('__ctx), + HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX), + }; + + // no_context impl is able to derive by-field, which is closer to a perfect derive. + s.add_bounds(match mode { + HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics, + HashStableMode::NoContext => synstructure::AddBounds::Fields, }); - let discriminant = match s.ast().data { - syn::Data::Enum(_) => quote! { - ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); - }, - syn::Data::Struct(_) => quote! {}, - syn::Data::Union(_) => panic!("cannot derive on union"), + // For generic impl, add `where __CTX: HashStableContext`. + match mode { + HashStableMode::Normal => {} + HashStableMode::Generic => { + s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext }); + } + HashStableMode::NoContext => {} + } + + s.add_impl_generic(generic); + + let discriminant = hash_stable_discriminant(&mut s); + let body = hash_stable_body(&mut s); + + let context: syn::Type = match mode { + HashStableMode::Normal => { + parse_quote!(::rustc_query_system::ich::StableHashingContext<'__ctx>) + } + HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX), }; s.bound_impl( - quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>), + quote!( + ::rustc_data_structures::stable_hasher::HashStable< + #context + > + ), quote! { #[inline] fn hash_stable( &self, - __hcx: &mut __CTX, + __hcx: &mut #context, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { #discriminant match *self { #body } @@ -81,11 +120,18 @@ pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_ma ) } -pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { - let generic: syn::GenericParam = parse_quote!('__ctx); - s.add_bounds(synstructure::AddBounds::Generics); - s.add_impl_generic(generic); - let body = s.each(|bi| { +fn hash_stable_discriminant(s: &mut synstructure::Structure<'_>) -> proc_macro2::TokenStream { + match s.ast().data { + syn::Data::Enum(_) => quote! { + ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); + }, + syn::Data::Struct(_) => quote! {}, + syn::Data::Union(_) => panic!("cannot derive on union"), + } +} + +fn hash_stable_body(s: &mut synstructure::Structure<'_>) -> proc_macro2::TokenStream { + s.each(|bi| { let attrs = parse_attributes(bi.ast()); if attrs.ignore { quote! {} @@ -98,31 +144,5 @@ pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To #bi.hash_stable(__hcx, __hasher); } } - }); - - let discriminant = match s.ast().data { - syn::Data::Enum(_) => quote! { - ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); - }, - syn::Data::Struct(_) => quote! {}, - syn::Data::Union(_) => panic!("cannot derive on union"), - }; - - s.bound_impl( - quote!( - ::rustc_data_structures::stable_hasher::HashStable< - ::rustc_query_system::ich::StableHashingContext<'__ctx>, - > - ), - quote! { - #[inline] - fn hash_stable( - &self, - __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>, - __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { - #discriminant - match *self { #body } - } - }, - ) + }) } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 193dbd75f..f558b74be 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -19,13 +19,15 @@ mod current_version; mod diagnostics; mod hash_stable; mod lift; -mod newtype; mod query; mod serialize; mod symbols; mod type_foldable; mod type_visitable; +// Reads the rust version (e.g. "1.75.0") from the CFG_RELEASE env var and +// produces a `RustcVersion` literal containing that version (e.g. +// `RustcVersion { major: 1, minor: 75, patch: 0 }`). #[proc_macro] pub fn current_rustc_version(input: TokenStream) -> TokenStream { current_version::current_version(input) @@ -41,32 +43,18 @@ 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, spec_option_partial_eq)] -pub fn newtype_index(input: TokenStream) -> TokenStream { - newtype::newtype(input) -} - decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive); decl_derive!( [HashStable_Generic, attributes(stable_hasher)] => hash_stable::hash_stable_generic_derive ); +decl_derive!( + [HashStable_NoContext] => + /// `HashStable` implementation that has no `HashStableContext` bound and + /// which adds `where` bounds for `HashStable` based off of fields and not + /// generics. This is suitable for use in crates like `rustc_type_ir`. + hash_stable::hash_stable_no_context_derive +); decl_derive!([Decodable] => serialize::decodable_derive); decl_derive!([Encodable] => serialize::encodable_derive); diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index ad7ac7404..3dedd88fb 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -1,5 +1,5 @@ use quote::quote; -use syn::{self, parse_quote}; +use syn::parse_quote; pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs deleted file mode 100644 index 72b47de1a..000000000 --- a/compiler/rustc_macros/src/newtype.rs +++ /dev/null @@ -1,312 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::quote; -use syn::parse::*; -use syn::*; - -// 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 mut 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: Vec = Vec::new(); - let mut debug_format: Option = None; - let mut max = None; - let mut consts = Vec::new(); - let mut encodable = true; - let mut ord = true; - - attrs.retain(|attr| match attr.path().get_ident() { - Some(ident) => match &*ident.to_string() { - "custom_encodable" => { - encodable = false; - false - } - "no_ord_impl" => { - ord = false; - false - } - "max" => { - let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta - else { - panic!("#[max = NUMBER] attribute requires max value"); - }; - - if let Some(old) = max.replace(lit.lit.clone()) { - panic!("Specified multiple max: {old:?}"); - } - - false - } - "debug_format" => { - let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta - else { - panic!("#[debug_format = FMT] attribute requires a format"); - }; - - if let Some(old) = debug_format.replace(lit.lit.clone()) { - panic!("Specified multiple debug format options: {old:?}"); - } - - false - } - _ => true, - }, - _ => true, - }); - - loop { - // We've parsed everything that the user provided, so we're done - if body.is_empty() { - break; - } - - // Otherwise, we are parsing 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()?; - body.parse::()?; - consts.push(quote! { #(#const_attrs)* #vis const #const_name: #name = #name::from_u32(#const_val); }); - } - - let debug_format = - debug_format.unwrap_or_else(|| Lit::Str(LitStr::new("{}", Span::call_site()))); - - // 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) { - e.emit_u32(self.private); - } - } - } - } else { - quote! {} - }; - - if ord { - derive_paths.push(parse_quote!(Ord)); - derive_paths.push(parse_quote!(PartialOrd)); - } - - let step = if ord { - quote! { - 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 {} - } - } else { - quote! {} - }; - - let debug_impl = quote! { - impl ::std::fmt::Debug for #name { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(fmt, #debug_format, self.as_u32()) - } - } - }; - - let spec_partial_eq_impl = if let Lit::Int(max) = &max { - if let Ok(max_val) = max.base10_parse::() { - quote! { - impl core::option::SpecOptionPartialEq for #name { - #[inline] - fn eq(l: &Option, r: &Option) -> bool { - if #max_val < u32::MAX { - l.map(|i| i.private).unwrap_or(#max_val+1) == r.map(|i| i.private).unwrap_or(#max_val+1) - } else { - match (l, r) { - (Some(l), Some(r)) => r == l, - (None, None) => true, - _ => false - } - } - } - } - } - } else { - quote! {} - } - } else { - quote! {} - }; - - Ok(Self(quote! { - #(#attrs)* - #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)] - #[rustc_layout_scalar_valid_range_end(#max)] - #[rustc_pass_by_value] - #vis struct #name { - private: u32, - } - - #(#consts)* - - 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::Idx for #name { - #[inline] - fn new(value: usize) -> Self { - Self::from_usize(value) - } - - #[inline] - fn index(self) -> usize { - self.as_usize() - } - } - - #step - - #spec_partial_eq_impl - - 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() -} diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs index 4129712a6..488d4504a 100644 --- a/compiler/rustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -19,7 +19,9 @@ //! ```bash //! cargo install cargo-expand # this is necessary only once //! cd compiler/rustc_span -//! cargo expand > /tmp/rustc_span.rs # it's a big file +//! # The specific version number in CFG_RELEASE doesn't matter. +//! # The output is large. +//! CFG_RELEASE="0.0.0" cargo +nightly expand > /tmp/rustc_span.rs //! ``` use proc_macro2::{Span, TokenStream}; @@ -83,7 +85,9 @@ impl Parse for Value { } } Expr::Macro(expr) => { - if expr.mac.path.is_ident("env") && let Ok(lit) = expr.mac.parse_body() { + if expr.mac.path.is_ident("env") + && let Ok(lit) = expr.mac.parse_body() + { return Ok(Value::Env(lit, expr.mac.clone())); } } @@ -318,13 +322,4 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec) { }; (output, errors.list) - - // To see the generated code, use the "cargo expand" command. - // Do this once to install: - // cargo install cargo-expand - // - // Then, cd to rustc_span and run: - // cargo expand > /tmp/rustc_span_expanded.rs - // - // and read that file. } -- cgit v1.2.3