Auto merge of #117731 - nnethercote:rustc_macros, r=Nilstrieb
`rustc_macros` cleanups Just some improvements I found while reading over this code. r? `@Nilstrieb`
This commit is contained in:
commit
fa14810f21
@ -1,37 +1,16 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
use syn::{parenthesized, parse_macro_input, LitStr, Token};
|
|
||||||
|
|
||||||
pub struct Input {
|
pub(crate) fn current_version(_input: TokenStream) -> TokenStream {
|
||||||
variable: LitStr,
|
let env_var = "CFG_RELEASE";
|
||||||
}
|
TokenStream::from(match RustcVersion::parse_cfg_release(env_var) {
|
||||||
|
|
||||||
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<Self> {
|
|
||||||
let paren;
|
|
||||||
input.parse::<kw::env>()?;
|
|
||||||
input.parse::<Token![!]>()?;
|
|
||||||
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) {
|
|
||||||
Ok(RustcVersion { major, minor, patch }) => quote!(
|
Ok(RustcVersion { major, minor, patch }) => quote!(
|
||||||
|
// The produced literal has type `rustc_session::RustcVersion`.
|
||||||
Self { major: #major, minor: #minor, patch: #patch }
|
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 {
|
impl RustcVersion {
|
||||||
fn parse_env_var(env_var: &LitStr) -> Result<Self, Box<dyn std::error::Error>> {
|
fn parse_cfg_release(env_var: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let value = proc_macro::tracked_env::var(env_var.value())?;
|
let value = proc_macro::tracked_env::var(env_var)?;
|
||||||
Self::parse_str(&value)
|
Self::parse_str(&value)
|
||||||
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
|
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
|
||||||
}
|
}
|
||||||
|
@ -229,8 +229,8 @@ fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
// We need to make sure that the same diagnostic slug can be used multiple times without causing an
|
// We need to make sure that the same diagnostic slug can be used multiple times without
|
||||||
// error, so just have a global counter here.
|
// causing an error, so just have a global counter here.
|
||||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
let slug = slug.get_ident().unwrap();
|
let slug = slug.get_ident().unwrap();
|
||||||
let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed));
|
let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed));
|
||||||
|
@ -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
|
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
|
||||||
/// has the actual diagnostic message.
|
/// has the actual diagnostic message.
|
||||||
pub slug: SpannedOption<Path>,
|
pub slug: SpannedOption<Path>,
|
||||||
|
|
||||||
/// Error codes are a optional part of the struct attribute - this is only set to detect
|
/// Error codes are a optional part of the struct attribute - this is only set to detect
|
||||||
/// multiple specifications.
|
/// multiple specifications.
|
||||||
pub code: SpannedOption<()>,
|
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
|
/// 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
|
/// 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.
|
/// 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
|
where
|
||||||
F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream,
|
F: for<'a, 'v> Fn(DiagnosticDeriveVariantBuilder<'a>, &VariantInfo<'v>) -> TokenStream,
|
||||||
{
|
{
|
||||||
@ -121,7 +122,7 @@ impl DiagnosticDeriveBuilder {
|
|||||||
impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||||
/// Generates calls to `code` and similar functions based on the attributes on the type or
|
/// Generates calls to `code` and similar functions based on the attributes on the type or
|
||||||
/// variant.
|
/// variant.
|
||||||
pub fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream {
|
pub(crate) fn preamble(&mut self, variant: &VariantInfo<'_>) -> TokenStream {
|
||||||
let ast = variant.ast();
|
let ast = variant.ast();
|
||||||
let attrs = &ast.attrs;
|
let attrs = &ast.attrs;
|
||||||
let preamble = attrs.iter().map(|attr| {
|
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
|
/// Generates calls to `span_label` and similar functions based on the attributes on fields or
|
||||||
/// calls to `set_arg` when no attributes are present.
|
/// 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! {};
|
let mut body = quote! {};
|
||||||
// Generate `set_arg` calls first..
|
// Generate `set_arg` calls first..
|
||||||
for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
|
for binding in variant.bindings().iter().filter(|bi| should_generate_set_arg(bi.ast())) {
|
||||||
|
@ -478,7 +478,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||||
let kind_slugs = self.identify_kind()?;
|
let kind_slugs = self.identify_kind()?;
|
||||||
if kind_slugs.is_empty() {
|
if kind_slugs.is_empty() {
|
||||||
if self.is_enum {
|
if self.is_enum {
|
||||||
|
@ -17,7 +17,7 @@ use synstructure::{BindingInfo, VariantInfo};
|
|||||||
use super::error::invalid_attr;
|
use super::error::invalid_attr;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
|
pub(crate) static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an ident of the form `__code_N` where `N` is incremented once with every call.
|
/// 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 {
|
match self {
|
||||||
FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(),
|
FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(),
|
||||||
}
|
}
|
||||||
@ -537,7 +537,7 @@ impl fmt::Display for SuggestionKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SuggestionKind {
|
impl SuggestionKind {
|
||||||
pub fn to_suggestion_style(&self) -> TokenStream {
|
pub(crate) fn to_suggestion_style(&self) -> TokenStream {
|
||||||
match self {
|
match self {
|
||||||
SuggestionKind::Normal => {
|
SuggestionKind::Normal => {
|
||||||
quote! { rustc_errors::SuggestionStyle::ShowCode }
|
quote! { rustc_errors::SuggestionStyle::ShowCode }
|
||||||
|
@ -38,33 +38,16 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
|
|||||||
attrs
|
attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
pub(crate) fn hash_stable_generic_derive(
|
||||||
|
mut s: synstructure::Structure<'_>,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
let generic: syn::GenericParam = parse_quote!(__CTX);
|
let generic: syn::GenericParam = parse_quote!(__CTX);
|
||||||
s.add_bounds(synstructure::AddBounds::Generics);
|
s.add_bounds(synstructure::AddBounds::Generics);
|
||||||
s.add_impl_generic(generic);
|
s.add_impl_generic(generic);
|
||||||
s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let discriminant = match s.ast().data {
|
let discriminant = hash_stable_discriminant(&mut s);
|
||||||
syn::Data::Enum(_) => quote! {
|
let body = hash_stable_body(&mut s);
|
||||||
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
|
|
||||||
},
|
|
||||||
syn::Data::Struct(_) => quote! {},
|
|
||||||
syn::Data::Union(_) => panic!("cannot derive on union"),
|
|
||||||
};
|
|
||||||
|
|
||||||
s.bound_impl(
|
s.bound_impl(
|
||||||
quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
|
quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
|
||||||
@ -81,32 +64,13 @@ pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_ma
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
pub(crate) fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||||
let generic: syn::GenericParam = parse_quote!('__ctx);
|
let generic: syn::GenericParam = parse_quote!('__ctx);
|
||||||
s.add_bounds(synstructure::AddBounds::Generics);
|
s.add_bounds(synstructure::AddBounds::Generics);
|
||||||
s.add_impl_generic(generic);
|
s.add_impl_generic(generic);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let discriminant = match s.ast().data {
|
let discriminant = hash_stable_discriminant(&mut s);
|
||||||
syn::Data::Enum(_) => quote! {
|
let body = hash_stable_body(&mut s);
|
||||||
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
|
|
||||||
},
|
|
||||||
syn::Data::Struct(_) => quote! {},
|
|
||||||
syn::Data::Union(_) => panic!("cannot derive on union"),
|
|
||||||
};
|
|
||||||
|
|
||||||
s.bound_impl(
|
s.bound_impl(
|
||||||
quote!(
|
quote!(
|
||||||
@ -126,3 +90,30 @@ pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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! {}
|
||||||
|
} else if let Some(project) = attrs.project {
|
||||||
|
quote! {
|
||||||
|
(&#bi.#project).hash_stable(__hcx, __hasher);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#bi.hash_stable(__hcx, __hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -26,6 +26,9 @@ mod symbols;
|
|||||||
mod type_foldable;
|
mod type_foldable;
|
||||||
mod type_visitable;
|
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]
|
#[proc_macro]
|
||||||
pub fn current_rustc_version(input: TokenStream) -> TokenStream {
|
pub fn current_rustc_version(input: TokenStream) -> TokenStream {
|
||||||
current_version::current_version(input)
|
current_version::current_version(input)
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
//! ```bash
|
//! ```bash
|
||||||
//! cargo install cargo-expand # this is necessary only once
|
//! cargo install cargo-expand # this is necessary only once
|
||||||
//! cd compiler/rustc_span
|
//! 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};
|
use proc_macro2::{Span, TokenStream};
|
||||||
@ -318,13 +320,4 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(output, errors.list)
|
(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.
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ pub struct RustcVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RustcVersion {
|
impl RustcVersion {
|
||||||
pub const CURRENT: Self = current_rustc_version!(env!("CFG_RELEASE"));
|
pub const CURRENT: Self = current_rustc_version!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RustcVersion {
|
impl Display for RustcVersion {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user