summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_macros
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_macros')
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs72
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs14
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs142
-rw-r--r--compiler/rustc_macros/src/lib.rs3
-rw-r--r--compiler/rustc_macros/src/newtype.rs26
-rw-r--r--compiler/rustc_macros/src/query.rs26
9 files changed, 241 insertions, 52 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index ef1985b96..684835d8c 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
use crate::diagnostics::utils::SetOnce;
use proc_macro2::TokenStream;
use quote::quote;
+use syn::spanned::Spanned;
use synstructure::Structure;
/// The central struct for constructing the `into_diagnostic` method from an annotated struct.
@@ -28,8 +29,8 @@ impl<'a> DiagnosticDerive<'a> {
let DiagnosticDerive { mut structure, mut builder } = self;
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
- let preamble = builder.preamble(&variant);
- let body = builder.body(&variant);
+ let preamble = builder.preamble(variant);
+ let body = builder.body(variant);
let diag = &builder.parent.diag;
let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
@@ -38,13 +39,24 @@ impl<'a> DiagnosticDerive<'a> {
let init = match builder.slug.value_ref() {
None => {
span_err(builder.span, "diagnostic slug not specified")
- .help(&format!(
+ .help(format!(
"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) => {
+ 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}_...`"
+ ))
+ .emit();
+ return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+ }
Some(slug) => {
quote! {
let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug);
@@ -69,6 +81,8 @@ impl<'a> DiagnosticDerive<'a> {
for @Self
where G: rustc_errors::EmissionGuarantee
{
+
+ #[track_caller]
fn into_diagnostic(
self,
#handler: &'__diagnostic_handler_sess rustc_errors::Handler
@@ -99,8 +113,8 @@ impl<'a> LintDiagnosticDerive<'a> {
let LintDiagnosticDerive { mut structure, mut builder } = self;
let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
- let preamble = builder.preamble(&variant);
- let body = builder.body(&variant);
+ let preamble = builder.preamble(variant);
+ let body = builder.body(variant);
let diag = &builder.parent.diag;
let formatting_init = &builder.formatting_init;
@@ -114,25 +128,41 @@ impl<'a> LintDiagnosticDerive<'a> {
let msg = builder.each_variant(&mut structure, |mut builder, variant| {
// Collect the slug by generating the preamble.
- let _ = builder.preamble(&variant);
+ let _ = builder.preamble(variant);
match builder.slug.value_ref() {
None => {
span_err(builder.span, "diagnostic slug not specified")
- .help(&format!(
+ .help(format!(
"specify the slug as the first argument to the attribute, such as \
`#[diag(compiletest_example)]`",
))
.emit();
- return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+ DiagnosticDeriveError::ErrorHandled.to_compile_error()
+ }
+ 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}_...`"
+ ))
+ .emit();
+ DiagnosticDeriveError::ErrorHandled.to_compile_error()
+ }
+ Some(slug) => {
+ quote! {
+ rustc_errors::fluent::#slug.into()
+ }
}
- Some(slug) => quote! { rustc_errors::fluent::#slug.into() },
}
});
let diag = &builder.diag;
structure.gen_impl(quote! {
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
+ #[track_caller]
fn decorate_lint<'__b>(
self,
#diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
@@ -148,3 +178,27 @@ impl<'a> LintDiagnosticDerive<'a> {
})
}
}
+
+struct Mismatch {
+ slug_name: String,
+ crate_name: String,
+ slug_prefix: String,
+}
+
+impl Mismatch {
+ /// Checks whether the slug starts with the crate name it's in.
+ fn check(slug: &syn::Path) -> Option<Mismatch> {
+ // If this is missing we're probably in a test, so bail.
+ let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
+
+ // If we're not in a "rustc_" crate, bail.
+ let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
+
+ let slug_name = slug.segments.first()?.ident.to_string();
+ if !slug_name.starts_with(slug_prefix) {
+ Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name })
+ } else {
+ None
+ }
+ }
+}
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 3ea83fd09..9f2ac5112 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -100,7 +100,7 @@ impl DiagnosticDeriveBuilder {
_ => variant.ast().ident.span().unwrap(),
};
let builder = DiagnosticDeriveVariantBuilder {
- parent: &self,
+ parent: self,
span,
field_map: build_field_mapping(variant),
formatting_init: TokenStream::new(),
@@ -211,7 +211,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
nested_iter.next();
}
Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
- Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| diag
+ Some(nested_attr) => throw_invalid_nested_attr!(attr, nested_attr, |diag| diag
.help("a diagnostic slug is required as the first argument")),
None => throw_invalid_attr!(attr, &meta, |diag| diag
.help("a diagnostic slug is required as the first argument")),
@@ -227,13 +227,13 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
..
})) => (value, path),
NestedMeta::Meta(Meta::Path(_)) => {
- invalid_nested_attr(attr, &nested_attr)
+ invalid_nested_attr(attr, nested_attr)
.help("diagnostic slug must be the first argument")
.emit();
continue;
}
_ => {
- invalid_nested_attr(attr, &nested_attr).emit();
+ invalid_nested_attr(attr, nested_attr).emit();
continue;
}
};
@@ -251,7 +251,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
});
}
- _ => invalid_nested_attr(attr, &nested_attr)
+ _ => invalid_nested_attr(attr, nested_attr)
.help("only `code` is a valid nested attributes following the slug")
.emit(),
}
@@ -427,9 +427,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
}
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
- if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+ if type_matches_path(info.ty, &["rustc_span", "Span"]) {
Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
- } else if type_is_unit(&info.ty) {
+ } else if type_is_unit(info.ty) {
Ok(self.add_subdiagnostic(&fn_ident, slug))
} else {
report_type_error(attr, "`Span` or `()`")?
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 0b1ededa7..4612f54e4 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -84,7 +84,7 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
}
}
-/// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
+/// Emit an error diagnostic for an invalid attribute (optionally performing additional decoration
/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
///
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
@@ -126,7 +126,7 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
}
}
-/// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
+/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
///
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 860340b43..78df0cd1d 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -129,7 +129,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
/// }
///
/// #[derive(Subdiagnostic)]
-/// #[suggestion_verbose(parser::raw_identifier)]
+/// #[suggestion(style = "verbose",parser::raw_identifier)]
/// pub struct RawIdentifierSuggestion<'tcx> {
/// #[primary_span]
/// span: Span,
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index fa0ca5a52..446aebe4f 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -409,7 +409,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
let mut code = None;
for nested_attr in list.nested.iter() {
let NestedMeta::Meta(ref meta) = nested_attr else {
- throw_invalid_nested_attr!(attr, &nested_attr);
+ throw_invalid_nested_attr!(attr, nested_attr);
};
let span = meta.span().unwrap();
@@ -427,7 +427,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
);
code.set_once((code_field, formatting_init), span);
}
- _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ _ => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
diag.help("`code` is the only valid nested attribute")
}),
}
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 374c795d0..da9023352 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -12,7 +12,7 @@ use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
use synstructure::{BindingInfo, VariantInfo};
-use super::error::invalid_nested_attr;
+use super::error::{invalid_attr, invalid_nested_attr};
thread_local! {
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
@@ -80,7 +80,7 @@ fn report_error_if_not_applied_to_ty(
path: &[&str],
ty_name: &str,
) -> Result<(), DiagnosticDeriveError> {
- if !type_matches_path(&info.ty, path) {
+ if !type_matches_path(info.ty, path) {
report_type_error(attr, ty_name)?;
}
@@ -105,8 +105,8 @@ pub(crate) fn report_error_if_not_applied_to_span(
attr: &Attribute,
info: &FieldInfo<'_>,
) -> Result<(), DiagnosticDeriveError> {
- if !type_matches_path(&info.ty, &["rustc_span", "Span"])
- && !type_matches_path(&info.ty, &["rustc_errors", "MultiSpan"])
+ if !type_matches_path(info.ty, &["rustc_span", "Span"])
+ && !type_matches_path(info.ty, &["rustc_errors", "MultiSpan"])
{
report_type_error(attr, "`Span` or `MultiSpan`")?;
}
@@ -472,16 +472,13 @@ pub(super) fn build_suggestion_code(
}
/// Possible styles for suggestion subdiagnostics.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
pub(super) enum SuggestionKind {
- /// `#[suggestion]`
Normal,
- /// `#[suggestion_short]`
Short,
- /// `#[suggestion_hidden]`
Hidden,
- /// `#[suggestion_verbose]`
Verbose,
+ ToolOnly,
}
impl FromStr for SuggestionKind {
@@ -489,15 +486,28 @@ impl FromStr for SuggestionKind {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
- "" => Ok(SuggestionKind::Normal),
- "_short" => Ok(SuggestionKind::Short),
- "_hidden" => Ok(SuggestionKind::Hidden),
- "_verbose" => Ok(SuggestionKind::Verbose),
+ "normal" => Ok(SuggestionKind::Normal),
+ "short" => Ok(SuggestionKind::Short),
+ "hidden" => Ok(SuggestionKind::Hidden),
+ "verbose" => Ok(SuggestionKind::Verbose),
+ "tool-only" => Ok(SuggestionKind::ToolOnly),
_ => Err(()),
}
}
}
+impl fmt::Display for SuggestionKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ SuggestionKind::Normal => write!(f, "normal"),
+ SuggestionKind::Short => write!(f, "short"),
+ SuggestionKind::Hidden => write!(f, "hidden"),
+ SuggestionKind::Verbose => write!(f, "verbose"),
+ SuggestionKind::ToolOnly => write!(f, "tool-only"),
+ }
+ }
+}
+
impl SuggestionKind {
pub fn to_suggestion_style(&self) -> TokenStream {
match self {
@@ -513,6 +523,19 @@ impl SuggestionKind {
SuggestionKind::Verbose => {
quote! { rustc_errors::SuggestionStyle::ShowAlways }
}
+ SuggestionKind::ToolOnly => {
+ quote! { rustc_errors::SuggestionStyle::CompletelyHidden }
+ }
+ }
+ }
+
+ fn from_suffix(s: &str) -> Option<Self> {
+ match s {
+ "" => Some(SuggestionKind::Normal),
+ "_short" => Some(SuggestionKind::Short),
+ "_hidden" => Some(SuggestionKind::Hidden),
+ "_verbose" => Some(SuggestionKind::Verbose),
+ _ => None,
}
}
}
@@ -565,25 +588,49 @@ impl SubdiagnosticKind {
let name = name.as_str();
let meta = attr.parse_meta()?;
+
let mut kind = match name {
"label" => SubdiagnosticKind::Label,
"note" => SubdiagnosticKind::Note,
"help" => SubdiagnosticKind::Help,
"warning" => SubdiagnosticKind::Warn,
_ => {
+ // Recover old `#[(multipart_)suggestion_*]` syntaxes
+ // FIXME(#100717): remove
if let Some(suggestion_kind) =
- name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+ name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
{
+ if suggestion_kind != SuggestionKind::Normal {
+ invalid_attr(attr, &meta)
+ .help(format!(
+ r#"Use `#[suggestion(..., style = "{}")]` instead"#,
+ suggestion_kind
+ ))
+ .emit();
+ }
+
SubdiagnosticKind::Suggestion {
- suggestion_kind,
+ suggestion_kind: SuggestionKind::Normal,
applicability: None,
code_field: new_code_ident(),
code_init: TokenStream::new(),
}
} else if let Some(suggestion_kind) =
- name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+ name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
{
- SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
+ if suggestion_kind != SuggestionKind::Normal {
+ invalid_attr(attr, &meta)
+ .help(format!(
+ r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#,
+ suggestion_kind
+ ))
+ .emit();
+ }
+
+ SubdiagnosticKind::MultipartSuggestion {
+ suggestion_kind: SuggestionKind::Normal,
+ applicability: None,
+ }
} else {
throw_invalid_attr!(attr, &meta);
}
@@ -621,6 +668,7 @@ impl SubdiagnosticKind {
};
let mut code = None;
+ let mut suggestion_kind = None;
let mut nested_iter = nested.into_iter().peekable();
@@ -638,7 +686,7 @@ impl SubdiagnosticKind {
let meta = match nested_attr {
NestedMeta::Meta(ref meta) => meta,
NestedMeta::Lit(_) => {
- invalid_nested_attr(attr, &nested_attr).emit();
+ invalid_nested_attr(attr, nested_attr).emit();
continue;
}
};
@@ -650,7 +698,7 @@ impl SubdiagnosticKind {
let string_value = match meta {
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
- Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+ Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
diag.help("a diagnostic slug must be the first argument to the attribute")
}),
_ => None,
@@ -672,7 +720,7 @@ impl SubdiagnosticKind {
| SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
) => {
let Some(value) = string_value else {
- invalid_nested_attr(attr, &nested_attr).emit();
+ invalid_nested_attr(attr, nested_attr).emit();
continue;
};
@@ -682,26 +730,56 @@ impl SubdiagnosticKind {
});
applicability.set_once(value, span);
}
+ (
+ "style",
+ SubdiagnosticKind::Suggestion { .. }
+ | SubdiagnosticKind::MultipartSuggestion { .. },
+ ) => {
+ let Some(value) = string_value else {
+ invalid_nested_attr(attr, nested_attr).emit();
+ continue;
+ };
+
+ let value = value.value().parse().unwrap_or_else(|()| {
+ span_err(value.span().unwrap(), "invalid suggestion style")
+ .help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`")
+ .emit();
+ SuggestionKind::Normal
+ });
+
+ suggestion_kind.set_once(value, span);
+ }
// Invalid nested attribute
(_, SubdiagnosticKind::Suggestion { .. }) => {
- invalid_nested_attr(attr, &nested_attr)
- .help("only `code` and `applicability` are valid nested attributes")
+ invalid_nested_attr(attr, nested_attr)
+ .help(
+ "only `style`, `code` and `applicability` are valid nested attributes",
+ )
.emit();
}
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
- invalid_nested_attr(attr, &nested_attr)
- .help("only `applicability` is a valid nested attributes")
+ invalid_nested_attr(attr, nested_attr)
+ .help("only `style` and `applicability` are valid nested attributes")
.emit()
}
_ => {
- invalid_nested_attr(attr, &nested_attr).emit();
+ invalid_nested_attr(attr, nested_attr).emit();
}
}
}
match kind {
- SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
+ SubdiagnosticKind::Suggestion {
+ ref code_field,
+ ref mut code_init,
+ suggestion_kind: ref mut kind_field,
+ ..
+ } => {
+ if let Some(kind) = suggestion_kind.value() {
+ *kind_field = kind;
+ }
+
*code_init = if let Some(init) = code.value() {
init
} else {
@@ -709,11 +787,17 @@ impl SubdiagnosticKind {
quote! { let #code_field = std::iter::empty(); }
};
}
+ SubdiagnosticKind::MultipartSuggestion {
+ suggestion_kind: ref mut kind_field, ..
+ } => {
+ if let Some(kind) = suggestion_kind.value() {
+ *kind_field = kind;
+ }
+ }
SubdiagnosticKind::Label
| SubdiagnosticKind::Note
| SubdiagnosticKind::Help
- | SubdiagnosticKind::Warn
- | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+ | SubdiagnosticKind::Warn => {}
}
Ok(Some((kind, slug)))
@@ -746,5 +830,5 @@ pub(super) fn should_generate_set_arg(field: &Field) -> bool {
}
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
- attr.path.segments.last().unwrap().ident.to_string() == "doc"
+ attr.path.segments.last().unwrap().ident == "doc"
}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 36bda3e0f..ac916bb60 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -1,4 +1,5 @@
#![feature(allow_internal_unstable)]
+#![feature(if_let_guard)]
#![feature(never_type)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_span)]
@@ -47,7 +48,7 @@ pub fn symbols(input: TokenStream) -> TokenStream {
/// `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)]
+#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step, spec_option_partial_eq)]
pub fn newtype_index(input: TokenStream) -> TokenStream {
newtype::newtype(input)
}
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs
index 0a77b734c..fd3f52251 100644
--- a/compiler/rustc_macros/src/newtype.rs
+++ b/compiler/rustc_macros/src/newtype.rs
@@ -192,6 +192,30 @@ impl Parse for Newtype {
}
}
};
+ 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)*
@@ -293,6 +317,8 @@ impl Parse for Newtype {
#step
+ #spec_partial_eq_impl
+
impl From<#name> for u32 {
#[inline]
fn from(v: #name) -> u32 {
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 7cefafef9..789d83a0d 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -114,6 +114,9 @@ struct QueryModifiers {
/// Always remap the ParamEnv's constness before hashing.
remap_env_constness: Option<Ident>,
+
+ /// Generate a `feed` method to set the query's value from another query.
+ feedable: Option<Ident>,
}
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@@ -128,6 +131,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut depth_limit = None;
let mut separate_provide_extern = None;
let mut remap_env_constness = None;
+ let mut feedable = None;
while !input.is_empty() {
let modifier: Ident = input.parse()?;
@@ -187,6 +191,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
try_insert!(separate_provide_extern = modifier);
} else if modifier == "remap_env_constness" {
try_insert!(remap_env_constness = modifier);
+ } else if modifier == "feedable" {
+ try_insert!(feedable = modifier);
} else {
return Err(Error::new(modifier.span(), "unknown query modifier"));
}
@@ -206,6 +212,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
depth_limit,
separate_provide_extern,
remap_env_constness,
+ feedable,
})
}
@@ -296,6 +303,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
let mut query_stream = quote! {};
let mut query_description_stream = quote! {};
let mut query_cached_stream = quote! {};
+ let mut feedable_queries = quote! {};
for query in queries.0 {
let Query { name, arg, modifiers, .. } = &query;
@@ -350,6 +358,18 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
[#attribute_stream] fn #name(#arg) #result,
});
+ if modifiers.feedable.is_some() {
+ assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`.");
+ assert!(
+ modifiers.eval_always.is_none(),
+ "Query {name} cannot be both `feedable` and `eval_always`."
+ );
+ feedable_queries.extend(quote! {
+ #(#doc_comments)*
+ [#attribute_stream] fn #name(#arg) #result,
+ });
+ }
+
add_query_desc_cached_impl(&query, &mut query_description_stream, &mut query_cached_stream);
}
@@ -363,7 +383,11 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
}
}
}
-
+ macro_rules! rustc_feedable_queries {
+ ( $macro:ident! ) => {
+ $macro!(#feedable_queries);
+ }
+ }
pub mod descs {
use super::*;
#query_description_stream