summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_macros
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_macros
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_macros')
-rw-r--r--compiler/rustc_macros/Cargo.toml8
-rw-r--r--compiler/rustc_macros/src/current_version.rs59
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs38
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs4
-rw-r--r--compiler/rustc_macros/src/lib.rs7
-rw-r--r--compiler/rustc_macros/src/query.rs18
-rw-r--r--compiler/rustc_macros/src/serialize.rs30
-rw-r--r--compiler/rustc_macros/src/symbols.rs158
-rw-r--r--compiler/rustc_macros/src/symbols/tests.rs2
9 files changed, 259 insertions, 65 deletions
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index 17651ce95..d8d2bef49 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -1,13 +1,15 @@
[package]
name = "rustc_macros"
-version = "0.1.0"
+version = "0.0.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
-synstructure = "0.13.0"
-syn = { version = "2.0.9", features = ["full"] }
+# tidy-alphabetical-start
proc-macro2 = "1"
quote = "1"
+syn = { version = "2.0.9", features = ["full"] }
+synstructure = "0.13.0"
+# tidy-alphabetical-end
diff --git a/compiler/rustc_macros/src/current_version.rs b/compiler/rustc_macros/src/current_version.rs
new file mode 100644
index 000000000..5e3b91c17
--- /dev/null
+++ b/compiler/rustc_macros/src/current_version.rs
@@ -0,0 +1,59 @@
+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) {
+ Ok(RustcVersion { major, minor, patch }) => quote!(
+ Self { major: #major, minor: #minor, patch: #patch }
+ ),
+ Err(err) => syn::Error::new(Span::call_site(), err).into_compile_error(),
+ })
+}
+
+struct RustcVersion {
+ major: u16,
+ minor: u16,
+ patch: u16,
+}
+
+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())?;
+ Self::parse_str(&value)
+ .ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
+ }
+
+ fn parse_str(value: &str) -> Option<Self> {
+ // Ignore any suffixes such as "-dev" or "-nightly".
+ let mut components = value.split('-').next().unwrap().splitn(3, '.');
+ let major = components.next()?.parse().ok()?;
+ let minor = components.next()?.parse().ok()?;
+ let patch = components.next().unwrap_or("0").parse().ok()?;
+ Some(RustcVersion { major, minor, patch })
+ }
+}
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 04b7c5fee..1a8174bfd 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -42,19 +42,20 @@ impl<'a> DiagnosticDerive<'a> {
let init = match builder.slug.value_ref() {
None => {
span_err(builder.span, "diagnostic slug not specified")
- .help("specify the slug as the first argument to the `#[diag(...)]` \
- attribute, such as `#[diag(hir_analysis_example_error)]`")
+ .help(
+ "specify the slug as the first argument to the `#[diag(...)]` \
+ attribute, such as `#[diag(hir_analysis_example_error)]`",
+ )
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
- Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
+ Some(slug)
+ if let Some(Mismatch { slug_name, crate_name, slug_prefix }) =
+ Mismatch::check(slug) =>
+ {
span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
- .note(format!(
- "slug is `{slug_name}` but the crate name is `{crate_name}`"
- ))
- .help(format!(
- "expected a slug starting with `{slug_prefix}_...`"
- ))
+ .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`"))
+ .help(format!("expected a slug starting with `{slug_prefix}_...`"))
.emit();
return DiagnosticDeriveError::ErrorHandled.to_compile_error();
}
@@ -141,19 +142,20 @@ impl<'a> LintDiagnosticDerive<'a> {
match builder.slug.value_ref() {
None => {
span_err(builder.span, "diagnostic slug not specified")
- .help("specify the slug as the first argument to the attribute, such as \
- `#[diag(compiletest_example)]`")
+ .help(
+ "specify the slug as the first argument to the attribute, such as \
+ `#[diag(compiletest_example)]`",
+ )
.emit();
DiagnosticDeriveError::ErrorHandled.to_compile_error()
}
- Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => {
+ Some(slug)
+ if let Some(Mismatch { slug_name, crate_name, slug_prefix }) =
+ Mismatch::check(slug) =>
+ {
span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match")
- .note(format!(
- "slug is `{slug_name}` but the crate name is `{crate_name}`"
- ))
- .help(format!(
- "expected a slug starting with `{slug_prefix}_...`"
- ))
+ .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`"))
+ .help(format!("expected a slug starting with `{slug_prefix}_...`"))
.emit();
DiagnosticDeriveError::ErrorHandled.to_compile_error()
}
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 877e97450..877271ff0 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -577,7 +577,9 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
}
}
_ => {
- if let Some(span) = span_field && !no_span {
+ if let Some(span) = span_field
+ && !no_span
+ {
quote! { #diag.#name(#span, #message); }
} else {
quote! { #diag.#name(#message); }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 85829906f..193dbd75f 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -4,6 +4,7 @@
#![feature(never_type)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
+#![feature(proc_macro_tracked_env)]
#![allow(rustc::default_hash_types)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
@@ -14,6 +15,7 @@ use synstructure::decl_derive;
use proc_macro::TokenStream;
+mod current_version;
mod diagnostics;
mod hash_stable;
mod lift;
@@ -25,6 +27,11 @@ mod type_foldable;
mod type_visitable;
#[proc_macro]
+pub fn current_rustc_version(input: TokenStream) -> TokenStream {
+ current_version::current_version(input)
+}
+
+#[proc_macro]
pub fn rustc_queries(input: TokenStream) -> TokenStream {
query::rustc_queries(input)
}
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index d0d41c614..ad1980136 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -97,6 +97,9 @@ struct QueryModifiers {
/// A cycle error results in a delay_bug call
cycle_delay_bug: Option<Ident>,
+ /// A cycle error results in a stashed cycle error that can be unstashed and canceled later
+ cycle_stash: Option<Ident>,
+
/// Don't hash the result, instead just mark a query red if it runs
no_hash: Option<Ident>,
@@ -114,6 +117,11 @@ struct QueryModifiers {
/// Generate a `feed` method to set the query's value from another query.
feedable: Option<Ident>,
+
+ /// Forward the result on ensure if the query gets recomputed, and
+ /// return `Ok(())` otherwise. Only applicable to queries returning
+ /// `Result<(), ErrorGuaranteed>`
+ ensure_forwards_result_if_red: Option<Ident>,
}
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@@ -122,12 +130,14 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut desc = None;
let mut fatal_cycle = None;
let mut cycle_delay_bug = None;
+ let mut cycle_stash = None;
let mut no_hash = None;
let mut anon = None;
let mut eval_always = None;
let mut depth_limit = None;
let mut separate_provide_extern = None;
let mut feedable = None;
+ let mut ensure_forwards_result_if_red = None;
while !input.is_empty() {
let modifier: Ident = input.parse()?;
@@ -175,6 +185,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
try_insert!(fatal_cycle = modifier);
} else if modifier == "cycle_delay_bug" {
try_insert!(cycle_delay_bug = modifier);
+ } else if modifier == "cycle_stash" {
+ try_insert!(cycle_stash = modifier);
} else if modifier == "no_hash" {
try_insert!(no_hash = modifier);
} else if modifier == "anon" {
@@ -187,6 +199,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
try_insert!(separate_provide_extern = modifier);
} else if modifier == "feedable" {
try_insert!(feedable = modifier);
+ } else if modifier == "ensure_forwards_result_if_red" {
+ try_insert!(ensure_forwards_result_if_red = modifier);
} else {
return Err(Error::new(modifier.span(), "unknown query modifier"));
}
@@ -200,12 +214,14 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
desc,
fatal_cycle,
cycle_delay_bug,
+ cycle_stash,
no_hash,
anon,
eval_always,
depth_limit,
separate_provide_extern,
feedable,
+ ensure_forwards_result_if_red,
})
}
@@ -320,11 +336,13 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
fatal_cycle,
arena_cache,
cycle_delay_bug,
+ cycle_stash,
no_hash,
anon,
eval_always,
depth_limit,
separate_provide_extern,
+ ensure_forwards_result_if_red,
);
if modifiers.cache.is_some() {
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index ba75517d7..047066ac6 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -5,11 +5,16 @@ use syn::spanned::Spanned;
pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
let decoder_ty = quote! { __D };
- if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
- s.add_impl_generic(parse_quote! { 'tcx });
- }
- s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
- s.add_bounds(synstructure::AddBounds::Generics);
+ let bound = if s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+ quote! { <I = ::rustc_middle::ty::TyCtxt<'tcx>> }
+ } else if s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+ quote! { <I = I> }
+ } else {
+ quote! {}
+ };
+
+ s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder #bound });
+ s.add_bounds(synstructure::AddBounds::Fields);
decodable_body(s, decoder_ty)
}
@@ -97,12 +102,17 @@ fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream {
}
pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
- if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
- s.add_impl_generic(parse_quote! {'tcx});
- }
+ let bound = if s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+ quote! { <I = ::rustc_middle::ty::TyCtxt<'tcx>> }
+ } else if s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+ quote! { <I = I> }
+ } else {
+ quote! {}
+ };
+
let encoder_ty = quote! { __E };
- s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
- s.add_bounds(synstructure::AddBounds::Generics);
+ s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder #bound });
+ s.add_bounds(synstructure::AddBounds::Fields);
encodable_body(s, encoder_ty, false)
}
diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index 04facbf65..4129712a6 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream};
use quote::quote;
use std::collections::HashMap;
use syn::parse::{Parse, ParseStream, Result};
-use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token};
+use syn::{braced, punctuated::Punctuated, Expr, Ident, Lit, LitStr, Macro, Token};
#[cfg(test)]
mod tests;
@@ -53,21 +53,46 @@ impl Parse for Keyword {
struct Symbol {
name: Ident,
- value: Option<LitStr>,
+ value: Value,
+}
+
+enum Value {
+ SameAsName,
+ String(LitStr),
+ Env(LitStr, Macro),
+ Unsupported(Expr),
}
impl Parse for Symbol {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let name = input.parse()?;
- let value = match input.parse::<Token![:]>() {
- Ok(_) => Some(input.parse()?),
- Err(_) => None,
- };
+ let colon_token: Option<Token![:]> = input.parse()?;
+ let value = if colon_token.is_some() { input.parse()? } else { Value::SameAsName };
Ok(Symbol { name, value })
}
}
+impl Parse for Value {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let expr: Expr = input.parse()?;
+ match &expr {
+ Expr::Lit(expr) => {
+ if let Lit::Str(lit) = &expr.lit {
+ return Ok(Value::String(lit.clone()));
+ }
+ }
+ Expr::Macro(expr) => {
+ if expr.mac.path.is_ident("env") && let Ok(lit) = expr.mac.parse_body() {
+ return Ok(Value::Env(lit, expr.mac.clone()));
+ }
+ }
+ _ => {}
+ }
+ Ok(Value::Unsupported(expr))
+ }
+}
+
struct Input {
keywords: Punctuated<Keyword, Token![,]>,
symbols: Punctuated<Symbol, Token![,]>,
@@ -111,6 +136,37 @@ pub fn symbols(input: TokenStream) -> TokenStream {
output
}
+struct Preinterned {
+ idx: u32,
+ span_of_name: Span,
+}
+
+struct Entries {
+ map: HashMap<String, Preinterned>,
+}
+
+impl Entries {
+ fn with_capacity(capacity: usize) -> Self {
+ Entries { map: HashMap::with_capacity(capacity) }
+ }
+
+ fn insert(&mut self, span: Span, str: &str, errors: &mut Errors) -> u32 {
+ if let Some(prev) = self.map.get(str) {
+ errors.error(span, format!("Symbol `{str}` is duplicated"));
+ errors.error(prev.span_of_name, "location of previous definition".to_string());
+ prev.idx
+ } else {
+ let idx = self.len();
+ self.map.insert(str.to_string(), Preinterned { idx, span_of_name: span });
+ idx
+ }
+ }
+
+ fn len(&self) -> u32 {
+ u32::try_from(self.map.len()).expect("way too many symbols")
+ }
+}
+
fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
let mut errors = Errors::default();
@@ -127,20 +183,9 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
let mut keyword_stream = quote! {};
let mut symbols_stream = quote! {};
let mut prefill_stream = quote! {};
- let mut counter = 0u32;
- let mut keys =
- HashMap::<String, Span>::with_capacity(input.keywords.len() + input.symbols.len() + 10);
+ let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
let mut prev_key: Option<(Span, String)> = None;
- let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
- if let Some(prev_span) = keys.get(str) {
- errors.error(span, format!("Symbol `{str}` is duplicated"));
- errors.error(*prev_span, "location of previous definition".to_string());
- } else {
- keys.insert(str.to_string(), span);
- }
- };
-
let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
if let Some((prev_span, ref prev_str)) = prev_key {
if str < prev_str {
@@ -156,49 +201,98 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
let name = &keyword.name;
let value = &keyword.value;
let value_string = value.value();
- check_dup(keyword.name.span(), &value_string, &mut errors);
+ let idx = entries.insert(keyword.name.span(), &value_string, &mut errors);
prefill_stream.extend(quote! {
#value,
});
keyword_stream.extend(quote! {
- pub const #name: Symbol = Symbol::new(#counter);
+ pub const #name: Symbol = Symbol::new(#idx);
});
- counter += 1;
}
// Generate the listed symbols.
for symbol in input.symbols.iter() {
let name = &symbol.name;
+ check_order(symbol.name.span(), &name.to_string(), &mut errors);
+
let value = match &symbol.value {
- Some(value) => value.value(),
- None => name.to_string(),
+ Value::SameAsName => name.to_string(),
+ Value::String(lit) => lit.value(),
+ Value::Env(..) => continue, // in another loop below
+ Value::Unsupported(expr) => {
+ errors.list.push(syn::Error::new_spanned(
+ expr,
+ concat!(
+ "unsupported expression for symbol value; implement support for this in ",
+ file!(),
+ ),
+ ));
+ continue;
+ }
};
- check_dup(symbol.name.span(), &value, &mut errors);
- check_order(symbol.name.span(), &name.to_string(), &mut errors);
+ let idx = entries.insert(symbol.name.span(), &value, &mut errors);
prefill_stream.extend(quote! {
#value,
});
symbols_stream.extend(quote! {
- pub const #name: Symbol = Symbol::new(#counter);
+ pub const #name: Symbol = Symbol::new(#idx);
});
- counter += 1;
}
// Generate symbols for the strings "0", "1", ..., "9".
- let digits_base = counter;
- counter += 10;
for n in 0..10 {
let n = n.to_string();
- check_dup(Span::call_site(), &n, &mut errors);
+ entries.insert(Span::call_site(), &n, &mut errors);
prefill_stream.extend(quote! {
#n,
});
}
+ // Symbols whose value comes from an environment variable. It's allowed for
+ // these to have the same value as another symbol.
+ for symbol in &input.symbols {
+ let (env_var, expr) = match &symbol.value {
+ Value::Env(lit, expr) => (lit, expr),
+ Value::SameAsName | Value::String(_) | Value::Unsupported(_) => continue,
+ };
+
+ if !proc_macro::is_available() {
+ errors.error(
+ Span::call_site(),
+ "proc_macro::tracked_env is not available in unit test".to_owned(),
+ );
+ break;
+ }
+
+ let value = match proc_macro::tracked_env::var(env_var.value()) {
+ Ok(value) => value,
+ Err(err) => {
+ errors.list.push(syn::Error::new_spanned(expr, err));
+ continue;
+ }
+ };
+
+ let idx = if let Some(prev) = entries.map.get(&value) {
+ prev.idx
+ } else {
+ prefill_stream.extend(quote! {
+ #value,
+ });
+ entries.insert(symbol.name.span(), &value, &mut errors)
+ };
+
+ let name = &symbol.name;
+ symbols_stream.extend(quote! {
+ pub const #name: Symbol = Symbol::new(#idx);
+ });
+ }
+
+ let symbol_digits_base = entries.map["0"].idx;
+ let preinterned_symbols_count = entries.len();
let output = quote! {
- const SYMBOL_DIGITS_BASE: u32 = #digits_base;
- const PREINTERNED_SYMBOLS_COUNT: u32 = #counter;
+ const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base;
+ const PREINTERNED_SYMBOLS_COUNT: u32 = #preinterned_symbols_count;
#[doc(hidden)]
#[allow(non_upper_case_globals)]
diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs
index bd0c08a53..9c53453df 100644
--- a/compiler/rustc_macros/src/symbols/tests.rs
+++ b/compiler/rustc_macros/src/symbols/tests.rs
@@ -27,7 +27,7 @@ fn test_symbols() {
let body_tokens = m.mac.tokens.clone();
- test_symbols_macro(body_tokens, &[]);
+ test_symbols_macro(body_tokens, &["proc_macro::tracked_env is not available in unit test"]);
}
fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) {