Skip to content

rustc_macros cleanups #117731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 8 additions & 29 deletions compiler/rustc_macros/src/current_version.rs
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this was added just a couple of weeks ago in #117256 :D

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) {
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(),
})
}

Expand All @@ -42,8 +21,8 @@ struct RustcVersion {
}

impl RustcVersion {
fn parse_env_var(env_var: &LitStr) -> Result<Self, Box<dyn std::error::Error>> {
let value = proc_macro::tracked_env::var(env_var.value())?;
fn parse_cfg_release(env_var: &str) -> Result<Self, Box<dyn std::error::Error>> {
let value = proc_macro::tracked_env::var(env_var)?;
Self::parse_str(&value)
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_macros/src/diagnostics/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,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));
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Path>,

/// Error codes are a optional part of the struct attribute - this is only set to detect
/// multiple specifications.
pub code: SpannedOption<()>,
Expand All @@ -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,
{
Expand Down Expand Up @@ -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| {
Expand All @@ -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())) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?;
if kind_slugs.is_empty() {
if self.is_enum {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_macros/src/diagnostics/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use synstructure::{BindingInfo, VariantInfo};
use super::error::invalid_attr;

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.
Expand Down Expand Up @@ -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(),
}
Expand Down Expand Up @@ -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 }
Expand Down
79 changes: 35 additions & 44 deletions compiler/rustc_macros/src/hash_stable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,16 @@ fn parse_attributes(field: &syn::Field) -> Attributes {
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);
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);
}
}
});

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"),
};
let discriminant = hash_stable_discriminant(&mut s);
let body = hash_stable_body(&mut s);

s.bound_impl(
quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
Expand All @@ -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);
s.add_bounds(synstructure::AddBounds::Generics);
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 {
syn::Data::Enum(_) => quote! {
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
},
syn::Data::Struct(_) => quote! {},
syn::Data::Union(_) => panic!("cannot derive on union"),
};
let discriminant = hash_stable_discriminant(&mut s);
let body = hash_stable_body(&mut s);

s.bound_impl(
quote!(
Expand All @@ -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);
}
}
})
}
3 changes: 3 additions & 0 deletions compiler/rustc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ 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)
Expand Down
13 changes: 3 additions & 10 deletions compiler/rustc_macros/src/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -318,13 +320,4 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
};

(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.
}
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub struct RustcVersion {
}

impl RustcVersion {
pub const CURRENT: Self = current_rustc_version!(env!("CFG_RELEASE"));
pub const CURRENT: Self = current_rustc_version!();
}

impl Display for RustcVersion {
Expand Down