summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_macros/src')
-rw-r--r--compiler/rustc_macros/src/current_version.rs37
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs27
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs19
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs6
-rw-r--r--compiler/rustc_macros/src/hash_stable.rs140
-rw-r--r--compiler/rustc_macros/src/lib.rs32
-rw-r--r--compiler/rustc_macros/src/lift.rs2
-rw-r--r--compiler/rustc_macros/src/newtype.rs312
-rw-r--r--compiler/rustc_macros/src/symbols.rs17
10 files changed, 133 insertions, 461 deletions
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<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(),
})
}
@@ -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())
}
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<Path>,
+
/// 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<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 {
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<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.
@@ -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<Self> {
- let mut attrs = input.call(Attribute::parse_outer)?;
- let vis: Visibility = input.parse()?;
- input.parse::<Token![struct]>()?;
- let name: Ident = input.parse()?;
-
- let body;
- braced!(body in input);
-
- // Any additional `#[derive]` macro paths to apply
- let mut derive_paths: Vec<Path> = Vec::new();
- let mut debug_format: Option<Lit> = 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::<Token![const]>()?;
- let const_name: Ident = body.parse()?;
- body.parse::<Token![=]>()?;
- let const_val: Expr = body.parse()?;
- body.parse::<Token![;]>()?;
- 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<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
- fn decode(d: &mut D) -> Self {
- Self::from_u32(d.read_u32())
- }
- }
- impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> 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<usize> {
- <usize as ::std::iter::Step>::steps_between(
- &Self::index(*start),
- &Self::index(*end),
- )
- }
-
- #[inline]
- fn forward_checked(start: Self, u: usize) -> Option<Self> {
- Self::index(start).checked_add(u).map(Self::from_usize)
- }
-
- #[inline]
- fn backward_checked(start: Self, u: usize) -> Option<Self> {
- 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::<u32>() {
- quote! {
- impl core::option::SpecOptionPartialEq for #name {
- #[inline]
- fn eq(l: &Option<Self>, r: &Option<Self>) -> 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<usize> 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<usize> for #name {
- #[inline]
- fn from(value: usize) -> Self {
- Self::from_usize(value)
- }
- }
-
- impl From<u32> 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<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.
}