summaryrefslogtreecommitdiff
path: root/compiler/rustc_macros
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2023-03-27 13:44:06 +0000
committerDeadbeef <ent3rm4n@gmail.com>2023-04-06 04:55:58 +0000
commitaf74ef89934ad30b24132b464b6b4cf7cb0e1381 (patch)
tree60eaf705873a5d7a894449f56b090bddc751c693 /compiler/rustc_macros
parent33289132ecc1805250f63801fded10fceb2300d8 (diff)
downloadrust-af74ef89934ad30b24132b464b6b4cf7cb0e1381.tar.gz
migrate rustc_macros to syn 2.0
Diffstat (limited to 'compiler/rustc_macros')
-rw-r--r--compiler/rustc_macros/Cargo.toml4
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs152
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs55
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs78
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs186
-rw-r--r--compiler/rustc_macros/src/hash_stable.rs45
-rw-r--r--compiler/rustc_macros/src/newtype.rs10
-rw-r--r--compiler/rustc_macros/src/query.rs8
-rw-r--r--compiler/rustc_macros/src/type_foldable.rs27
-rw-r--r--compiler/rustc_macros/src/type_visitable.rs30
10 files changed, 257 insertions, 338 deletions
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index 547c8debb50..745983e7e86 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -10,8 +10,8 @@ proc-macro = true
annotate-snippets = "0.9"
fluent-bundle = "0.15.2"
fluent-syntax = "0.11"
-synstructure = "0.12.1"
-syn = { version = "1", features = ["full"] }
+synstructure = "0.13.0"
+syn = { version = "2", features = ["full"] }
proc-macro2 = "1"
quote = "1"
unic-langid = { version = "0.9.0", features = ["macros"] }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 7fbe3bc2888..fb75d87f8d2 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -1,8 +1,7 @@
#![deny(unused_must_use)]
use crate::diagnostics::error::{
- invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
- DiagnosticDeriveError,
+ span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
};
use crate::diagnostics::utils::{
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
@@ -11,9 +10,8 @@ use crate::diagnostics::utils::{
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
-use syn::{
- parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
-};
+use syn::Token;
+use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
use synstructure::{BindingInfo, Structure, VariantInfo};
/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
@@ -77,7 +75,7 @@ impl DiagnosticDeriveBuilder {
match ast.data {
syn::Data::Struct(..) | syn::Data::Enum(..) => (),
syn::Data::Union(..) => {
- span_err(span, "diagnostic derives can only be used on structs and enums");
+ span_err(span, "diagnostic derives can only be used on structs and enums").emit();
}
}
@@ -160,8 +158,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
};
if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag {
- let meta = attr.parse_meta()?;
- throw_invalid_attr!(attr, &meta, |diag| diag
+ throw_invalid_attr!(attr, |diag| diag
.help("consider creating a `Subdiagnostic` instead"));
}
@@ -191,71 +188,39 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
return Ok(quote! {});
}
- let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = attr.path().segments.last().unwrap().ident.to_string();
let name = name.as_str();
- let meta = attr.parse_meta()?;
- if name == "diag" {
- let Meta::List(MetaList { ref nested, .. }) = meta else {
- throw_invalid_attr!(
- attr,
- &meta
- );
- };
+ let mut first = true;
- let mut nested_iter = nested.into_iter().peekable();
+ if name == "diag" {
+ let mut tokens = TokenStream::new();
+ attr.parse_nested_meta(|nested| {
+ let path = &nested.path;
- match nested_iter.peek() {
- Some(NestedMeta::Meta(Meta::Path(slug))) => {
- self.slug.set_once(slug.clone(), slug.span().unwrap());
- nested_iter.next();
+ if first && (nested.input.is_empty() || nested.input.peek(Token![,])) {
+ self.slug.set_once(path.clone(), path.span().unwrap());
+ first = false;
+ return Ok(())
}
- Some(NestedMeta::Meta(Meta::NameValue { .. })) => {}
- 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")),
- };
- // Remaining attributes are optional, only `code = ".."` at the moment.
- let mut tokens = TokenStream::new();
- for nested_attr in nested_iter {
- let (value, path) = match nested_attr {
- NestedMeta::Meta(Meta::NameValue(MetaNameValue {
- lit: syn::Lit::Str(value),
- path,
- ..
- })) => (value, path),
- NestedMeta::Meta(Meta::Path(_)) => {
- invalid_nested_attr(attr, nested_attr)
- .help("diagnostic slug must be the first argument")
- .emit();
- continue;
- }
- _ => {
- invalid_nested_attr(attr, nested_attr).emit();
- continue;
- }
+ first = false;
+
+ let Ok(nested) = nested.value() else {
+ span_err(nested.input.span().unwrap(), "diagnostic slug must be the first argument").emit();
+ return Ok(())
};
- let nested_name = path.segments.last().unwrap().ident.to_string();
- // Struct attributes are only allowed to be applied once, and the diagnostic
- // changes will be set in the initialisation code.
- let span = value.span().unwrap();
- match nested_name.as_str() {
- "code" => {
- self.code.set_once((), span);
-
- let code = value.value();
- tokens.extend(quote! {
- #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
- });
- }
- _ => invalid_nested_attr(attr, nested_attr)
- .help("only `code` is a valid nested attributes following the slug")
- .emit(),
+ if path.is_ident("code") {
+ self.code.set_once((), path.span().unwrap());
+
+ let code = nested.parse::<TokenStream>()?;
+ tokens.extend(quote! {
+ #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
+ });
}
- }
+ Ok(())
+ })?;
return Ok(tokens);
}
@@ -270,7 +235,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
Ok(self.add_subdiagnostic(&fn_ident, slug))
}
SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
- throw_invalid_attr!(attr, &meta, |diag| diag
+ throw_invalid_attr!(attr, |diag| diag
.help("`#[label]` and `#[suggestion]` can only be applied to fields"));
}
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
@@ -309,7 +274,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
return quote! {};
}
- let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = attr.path().segments.last().unwrap().ident.to_string();
let needs_clone =
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
let (binding, needs_destructure) = if needs_clone {
@@ -343,11 +308,10 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
binding: TokenStream,
) -> Result<TokenStream, DiagnosticDeriveError> {
let diag = &self.parent.diag;
- let meta = attr.parse_meta()?;
- let ident = &attr.path.segments.last().unwrap().ident;
+ let ident = &attr.path().segments.last().unwrap().ident;
let name = ident.to_string();
- match (&meta, name.as_str()) {
+ match (&attr.meta, name.as_str()) {
// Don't need to do anything - by virtue of the attribute existing, the
// `set_arg` call will not be generated.
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
@@ -361,7 +325,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
});
}
DiagnosticDeriveKind::LintDiagnostic => {
- throw_invalid_attr!(attr, &meta, |diag| {
+ throw_invalid_attr!(attr, |diag| {
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
})
}
@@ -378,26 +342,34 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
return Ok(quote! { #diag.subdiagnostic(#binding); });
}
}
- (Meta::List(MetaList { ref nested, .. }), "subdiagnostic") => {
- if nested.len() == 1
- && let Some(NestedMeta::Meta(Meta::Path(path))) = nested.first()
- && path.is_ident("eager") {
- let handler = match &self.parent.kind {
- DiagnosticDeriveKind::Diagnostic { handler } => handler,
- DiagnosticDeriveKind::LintDiagnostic => {
- throw_invalid_attr!(attr, &meta, |diag| {
- diag.help("eager subdiagnostics are not supported on lints")
- })
- }
- };
- return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
- } else {
- throw_invalid_attr!(attr, &meta, |diag| {
- diag.help(
- "`eager` is the only supported nested attribute for `subdiagnostic`",
- )
- })
+ (Meta::List(meta_list), "subdiagnostic") => {
+ let err = || {
+ span_err(
+ meta_list.span().unwrap(),
+ "`eager` is the only supported nested attribute for `subdiagnostic`",
+ )
+ .emit();
+ };
+
+ let Ok(p): Result<Path, _> = meta_list.parse_args() else {
+ err();
+ return Ok(quote! {});
+ };
+
+ if !p.is_ident("eager") {
+ err();
+ return Ok(quote! {});
}
+
+ let handler = match &self.parent.kind {
+ DiagnosticDeriveKind::Diagnostic { handler } => handler,
+ DiagnosticDeriveKind::LintDiagnostic => {
+ throw_invalid_attr!(attr, |diag| {
+ diag.help("eager subdiagnostics are not supported on lints")
+ })
+ }
+ };
+ return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
}
_ => (),
}
@@ -432,7 +404,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
code_init,
} => {
if let FieldInnerTy::Vec(_) = info.ty {
- throw_invalid_attr!(attr, &meta, |diag| {
+ throw_invalid_attr!(attr, |diag| {
diag
.note("`#[suggestion(...)]` applied to `Vec` field is ambiguous")
.help("to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]`")
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 2d62d593163..b37dc826d28 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -1,7 +1,7 @@
use proc_macro::{Diagnostic, Level, MultiSpan};
use proc_macro2::TokenStream;
use quote::quote;
-use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
+use syn::{spanned::Spanned, Attribute, Error as SynError, Meta};
#[derive(Debug)]
pub(crate) enum DiagnosticDeriveError {
@@ -53,6 +53,7 @@ fn path_to_string(path: &syn::Path) -> String {
}
/// Returns an error diagnostic on span `span` with msg `msg`.
+#[must_use]
pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
Diagnostic::spanned(span, Level::Error, msg)
}
@@ -72,10 +73,10 @@ macro_rules! throw_span_err {
pub(crate) use throw_span_err;
/// Returns an error diagnostic for an invalid attribute.
-pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
+pub(crate) fn invalid_attr(attr: &Attribute) -> Diagnostic {
let span = attr.span().unwrap();
- let path = path_to_string(&attr.path);
- match meta {
+ let path = path_to_string(attr.path());
+ match attr.meta {
Meta::Path(_) => span_err(span, &format!("`#[{path}]` is not a valid attribute")),
Meta::NameValue(_) => {
span_err(span, &format!("`#[{path} = ...]` is not a valid attribute"))
@@ -89,51 +90,11 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
///
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
macro_rules! throw_invalid_attr {
- ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
- ($attr:expr, $meta:expr, $f:expr) => {{
- let diag = crate::diagnostics::error::invalid_attr($attr, $meta);
+ ($attr:expr) => {{ throw_invalid_attr!($attr, |diag| diag) }};
+ ($attr:expr, $f:expr) => {{
+ let diag = crate::diagnostics::error::invalid_attr($attr);
return Err(crate::diagnostics::error::_throw_err(diag, $f));
}};
}
pub(crate) use throw_invalid_attr;
-
-/// Returns an error diagnostic for an invalid nested attribute.
-pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diagnostic {
- let name = attr.path.segments.last().unwrap().ident.to_string();
- let name = name.as_str();
-
- let span = nested.span().unwrap();
- let meta = match nested {
- syn::NestedMeta::Meta(meta) => meta,
- syn::NestedMeta::Lit(_) => {
- return span_err(span, &format!("`#[{name}(\"...\")]` is not a valid attribute"));
- }
- };
-
- let span = meta.span().unwrap();
- let path = path_to_string(meta.path());
- match meta {
- Meta::NameValue(..) => {
- span_err(span, &format!("`#[{name}({path} = ...)]` is not a valid attribute"))
- }
- Meta::Path(..) => span_err(span, &format!("`#[{name}({path})]` is not a valid attribute")),
- Meta::List(..) => {
- span_err(span, &format!("`#[{name}({path}(...))]` is not a valid attribute"))
- }
- }
-}
-
-/// 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>`:
-macro_rules! throw_invalid_nested_attr {
- ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
- ($attr:expr, $nested_attr:expr, $f:expr) => {{
- let diag = crate::diagnostics::error::invalid_nested_attr($attr, $nested_attr);
- return Err(crate::diagnostics::error::_throw_err(diag, $f));
- }};
-}
-
-pub(crate) use throw_invalid_nested_attr;
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 90660fc1f93..2f42a3b0bd4 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -1,8 +1,7 @@
#![deny(unused_must_use)]
use crate::diagnostics::error::{
- invalid_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
- DiagnosticDeriveError,
+ invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
};
use crate::diagnostics::utils::{
build_field_mapping, is_doc_comment, new_code_ident,
@@ -11,7 +10,7 @@ use crate::diagnostics::utils::{
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
-use syn::{spanned::Spanned, Attribute, Meta, MetaList, NestedMeta, Path};
+use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
@@ -39,7 +38,8 @@ impl SubdiagnosticDeriveBuilder {
span_err(
span,
"`#[derive(Subdiagnostic)]` can only be used on structs and enums",
- );
+ )
+ .emit();
}
}
@@ -192,7 +192,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
};
let Some(slug) = slug else {
- let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = attr.path().segments.last().unwrap().ident.to_string();
let name = name.as_str();
throw_span_err!(
@@ -265,17 +265,18 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
info: FieldInfo<'_>,
clone_suggestion_code: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
- let meta = attr.parse_meta()?;
- match meta {
- Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path),
- Meta::List(list @ MetaList { .. }) => self.generate_field_code_inner_list(
+ match &attr.meta {
+ Meta::Path(path) => {
+ self.generate_field_code_inner_path(kind_stats, attr, info, path.clone())
+ }
+ Meta::List(list) => self.generate_field_code_inner_list(
kind_stats,
attr,
info,
list,
clone_suggestion_code,
),
- _ => throw_invalid_attr!(attr, &meta),
+ _ => throw_invalid_attr!(attr),
}
}
@@ -296,7 +297,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
"skip_arg" => Ok(quote! {}),
"primary_span" => {
if kind_stats.has_multipart_suggestion {
- invalid_attr(attr, &Meta::Path(path))
+ invalid_attr(attr)
.help(
"multipart suggestions use one or more `#[suggestion_part]`s rather \
than one `#[primary_span]`",
@@ -309,7 +310,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
// FIXME(#100717): support `Option<Span>` on `primary_span` like in the
// diagnostic derive
if !matches!(info.ty, FieldInnerTy::Plain(_)) {
- throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
+ throw_invalid_attr!(attr, |diag| {
let diag = diag.note("there must be exactly one primary span");
if kind_stats.has_normal_suggestion {
@@ -335,7 +336,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
.emit();
} else {
- invalid_attr(attr, &Meta::Path(path))
+ invalid_attr(attr)
.help(
"`#[suggestion_part(...)]` is only valid in multipart suggestions, \
use `#[primary_span]` instead",
@@ -375,7 +376,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
span_attrs.push("primary_span")
}
- invalid_attr(attr, &Meta::Path(path))
+ invalid_attr(attr)
.help(format!(
"only `{}`, `applicability` and `skip_arg` are valid field attributes",
span_attrs.join(", ")
@@ -394,7 +395,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
kind_stats: KindsStatistics,
attr: &Attribute,
info: FieldInfo<'_>,
- list: MetaList,
+ list: &MetaList,
clone_suggestion_code: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
let span = attr.span().unwrap();
@@ -405,7 +406,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
match name {
"suggestion_part" => {
if !kind_stats.has_multipart_suggestion {
- throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+ throw_invalid_attr!(attr, |diag| {
diag.help(
"`#[suggestion_part(...)]` is only valid in multipart suggestions",
)
@@ -417,31 +418,26 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
report_error_if_not_applied_to_span(attr, &info)?;
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);
- };
-
- let span = meta.span().unwrap();
- let nested_name = meta.path().segments.last().unwrap().ident.to_string();
- let nested_name = nested_name.as_str();
-
- match nested_name {
- "code" => {
- let code_field = new_code_ident();
- let formatting_init = build_suggestion_code(
- &code_field,
- meta,
- self,
- AllowMultipleAlternatives::No,
- );
- code.set_once((code_field, formatting_init), span);
- }
- _ => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
- diag.help("`code` is the only valid nested attribute")
- }),
+
+ list.parse_nested_meta(|nested| {
+ if nested.path.is_ident("code") {
+ let code_field = new_code_ident();
+ let formatting_init = build_suggestion_code(
+ &code_field,
+ nested,
+ self,
+ AllowMultipleAlternatives::No,
+ );
+ code.set_once((code_field, formatting_init), span);
+ } else {
+ span_err(
+ nested.path.span().unwrap(),
+ "`code` is the only valid nested attribute",
+ )
+ .emit();
}
- }
+ Ok(())
+ })?;
let Some((code_field, formatting_init)) = code.value() else {
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
@@ -458,7 +454,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
};
Ok(quote! { suggestions.push((#binding, #code_field)); })
}
- _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
+ _ => throw_invalid_attr!(attr, |diag| {
let mut span_attrs = vec![];
if kind_stats.has_multipart_suggestion {
span_attrs.push("suggestion_part");
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 65bb154d7f3..38292df6d85 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -1,5 +1,5 @@
use crate::diagnostics::error::{
- span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
+ span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
};
use proc_macro::Span;
use proc_macro2::{Ident, TokenStream};
@@ -8,11 +8,13 @@ use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap};
use std::fmt;
use std::str::FromStr;
+use syn::meta::ParseNestedMeta;
+use syn::punctuated::Punctuated;
+use syn::{parenthesized, LitStr, Path, Token};
use syn::{spanned::Spanned, Attribute, Field, Meta, Type, TypeTuple};
-use syn::{MetaList, MetaNameValue, NestedMeta, Path};
use synstructure::{BindingInfo, VariantInfo};
-use super::error::{invalid_attr, invalid_nested_attr};
+use super::error::invalid_attr;
thread_local! {
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
@@ -60,8 +62,8 @@ pub(crate) fn report_type_error(
attr: &Attribute,
ty_name: &str,
) -> Result<!, DiagnosticDeriveError> {
- let name = attr.path.segments.last().unwrap().ident.to_string();
- let meta = attr.parse_meta()?;
+ let name = attr.path().segments.last().unwrap().ident.to_string();
+ let meta = &attr.meta;
throw_span_err!(
attr.span().unwrap(),
@@ -422,55 +424,53 @@ pub(super) enum AllowMultipleAlternatives {
/// `#[suggestion*(code("foo", "bar"))]` attribute field
pub(super) fn build_suggestion_code(
code_field: &Ident,
- meta: &Meta,
+ nested: ParseNestedMeta<'_>,
fields: &impl HasFieldMap,
allow_multiple: AllowMultipleAlternatives,
) -> TokenStream {
- let values = match meta {
- // `code = "foo"`
- Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => vec![s],
- // `code("foo", "bar")`
- Meta::List(MetaList { nested, .. }) => {
+ let values = match (|| {
+ let values: Vec<LitStr> = if let Ok(val) = nested.value() {
+ vec![val.parse()?]
+ } else {
+ let content;
+ parenthesized!(content in nested.input);
+
if let AllowMultipleAlternatives::No = allow_multiple {
span_err(
- meta.span().unwrap(),
+ nested.input.span().unwrap(),
"expected exactly one string literal for `code = ...`",
)
.emit();
vec![]
- } else if nested.is_empty() {
- span_err(
- meta.span().unwrap(),
- "expected at least one string literal for `code(...)`",
- )
- .emit();
- vec![]
} else {
- nested
- .into_iter()
- .filter_map(|item| {
- if let NestedMeta::Lit(syn::Lit::Str(s)) = item {
- Some(s)
- } else {
- span_err(
- item.span().unwrap(),
- "`code(...)` must contain only string literals",
- )
- .emit();
- None
- }
- })
- .collect()
+ let literals = Punctuated::<LitStr, Token![,]>::parse_terminated(&content);
+
+ match literals {
+ Ok(p) if p.is_empty() => {
+ span_err(
+ content.span().unwrap(),
+ "expected at least one string literal for `code(...)`",
+ )
+ .emit();
+ vec![]
+ }
+ Ok(p) => p.into_iter().collect(),
+ Err(_) => {
+ span_err(
+ content.span().unwrap(),
+ "`code(...)` must contain only string literals",
+ )
+ .emit();
+ vec![]
+ }
+ }
}
- }
- _ => {
- span_err(
- meta.span().unwrap(),
- r#"`code = "..."`/`code(...)` must contain only string literals"#,
- )
- .emit();
- vec![]
- }
+ };
+
+ Ok(values)
+ })() {
+ Ok(x) => x,
+ Err(e) => return e.into_compile_error(),
};
if let AllowMultipleAlternatives::Yes = allow_multiple {
@@ -601,11 +601,9 @@ impl SubdiagnosticKind {
let span = attr.span().unwrap();
- let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = attr.path().segments.last().unwrap().ident.to_string();
let name = name.as_str();
- let meta = attr.parse_meta()?;
-
let mut kind = match name {
"label" => SubdiagnosticKind::Label,
"note" => SubdiagnosticKind::Note,
@@ -618,7 +616,7 @@ impl SubdiagnosticKind {
name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
{
if suggestion_kind != SuggestionKind::Normal {
- invalid_attr(attr, &meta)
+ invalid_attr(attr)
.help(format!(
r#"Use `#[suggestion(..., style = "{suggestion_kind}")]` instead"#
))
@@ -635,7 +633,7 @@ impl SubdiagnosticKind {
name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
{
if suggestion_kind != SuggestionKind::Normal {
- invalid_attr(attr, &meta)
+ invalid_attr(attr)
.help(format!(
r#"Use `#[multipart_suggestion(..., style = "{suggestion_kind}")]` instead"#
))
@@ -647,16 +645,16 @@ impl SubdiagnosticKind {
applicability: None,
}
} else {
- throw_invalid_attr!(attr, &meta);
+ throw_invalid_attr!(attr);
}
}
};
- let nested = match meta {
- Meta::List(MetaList { ref nested, .. }) => {
+ let list = match &attr.meta {
+ Meta::List(list) => {
// An attribute with properties, such as `#[suggestion(code = "...")]` or
// `#[error(some::slug)]`
- nested
+ list
}
Meta::Path(_) => {
// An attribute without a slug or other properties, such as `#[note]` - return
@@ -678,52 +676,51 @@ impl SubdiagnosticKind {
}
}
_ => {
- throw_invalid_attr!(attr, &meta)
+ throw_invalid_attr!(attr)
}
};
let mut code = None;
let mut suggestion_kind = None;
- let mut nested_iter = nested.into_iter().peekable();
+ let mut first = true;
+ let mut slug = None;
- // Peek at the first nested attribute: if it's a slug path, consume it.
- let slug = if let Some(NestedMeta::Meta(Meta::Path(path))) = nested_iter.peek() {
- let path = path.clone();
- // Advance the iterator.
- nested_iter.next();
- Some(path)
- } else {
- None
- };
-
- for nested_attr in nested_iter {
- let meta = match nested_attr {
- NestedMeta::Meta(ref meta) => meta,
- NestedMeta::Lit(_) => {
- invalid_nested_attr(attr, nested_attr).emit();
- continue;
+ list.parse_nested_meta(|nested| {
+ if nested.input.is_empty() || nested.input.peek(Token![,]) {
+ if first {
+ slug = Some(nested.path);
+ } else {
+ span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit();
}
- };
- let span = meta.span().unwrap();
- let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+ first = false;
+ return Ok(());
+ }
+
+ first = false;
+
+ let nested_name = nested.path.segments.last().unwrap().ident.to_string();
let nested_name = nested_name.as_str();
- let string_value = match meta {
- Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => Some(value),
+ let path_span = nested.path.span().unwrap();
+ let val_span = nested.input.span().unwrap();
- Meta::Path(_) => throw_invalid_nested_attr!(attr, nested_attr, |diag| {
- diag.help("a diagnostic slug must be the first argument to the attribute")
- }),
- _ => None,
- };
+ macro get_string() {
+ {
+ let Ok(value) = nested.value().and_then(|x| x.parse::<LitStr>()) else {
+ span_err(val_span, "expected `= \"xxx\"`").emit();
+ return Ok(());
+ };
+ value
+ }
+ }
match (nested_name, &mut kind) {
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
let code_init = build_suggestion_code(
code_field,
- meta,
+ nested,
fields,
AllowMultipleAlternatives::Yes,
);
@@ -734,13 +731,9 @@ impl SubdiagnosticKind {
SubdiagnosticKind::Suggestion { ref mut applicability, .. }
| SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. },
) => {
- let Some(value) = string_value else {
- invalid_nested_attr(attr, nested_attr).emit();
- continue;
- };
-
+ let value = get_string!();
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
- span_err(span, "invalid applicability").emit();
+ span_err(value.span().unwrap(), "invalid applicability").emit();
Applicability::Unspecified
});
applicability.set_once(value, span);
@@ -750,10 +743,7 @@ impl SubdiagnosticKind {
SubdiagnosticKind::Suggestion { .. }
| SubdiagnosticKind::MultipartSuggestion { .. },
) => {
- let Some(value) = string_value else {
- invalid_nested_attr(attr, nested_attr).emit();
- continue;
- };
+ let value = get_string!();
let value = value.value().parse().unwrap_or_else(|()| {
span_err(value.span().unwrap(), "invalid suggestion style")
@@ -767,22 +757,24 @@ impl SubdiagnosticKind {
// Invalid nested attribute
(_, SubdiagnosticKind::Suggestion { .. }) => {
- invalid_nested_attr(attr, nested_attr)
+ span_err(path_span, "invalid nested attribute")
.help(
"only `style`, `code` and `applicability` are valid nested attributes",
)
.emit();
}
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
- invalid_nested_attr(attr, nested_attr)
+ span_err(path_span, "invalid nested attribute")
.help("only `style` and `applicability` are valid nested attributes")
- .emit()
+ .emit();
}
_ => {
- invalid_nested_attr(attr, nested_attr).emit();
+ span_err(path_span, "invalid nested attribute").emit();
}
}
- }
+
+ Ok(())
+ })?;
match kind {
SubdiagnosticKind::Suggestion {
@@ -845,5 +837,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 == "doc"
+ attr.path().segments.last().unwrap().ident == "doc"
}
diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs
index 63bdcea87f8..75a2f7009c2 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 quote::quote;
-use syn::{self, parse_quote, Meta, NestedMeta};
+use syn::{self, parse_quote};
struct Attributes {
ignore: bool,
@@ -10,32 +10,29 @@ struct Attributes {
fn parse_attributes(field: &syn::Field) -> Attributes {
let mut attrs = Attributes { ignore: false, project: None };
for attr in &field.attrs {
- if let Ok(meta) = attr.parse_meta() {
- if !meta.path().is_ident("stable_hasher") {
- continue;
+ let meta = &attr.meta;
+ if !meta.path().is_ident("stable_hasher") {
+ continue;
+ }
+ let mut any_attr = false;
+ let _ = attr.parse_nested_meta(|nested| {
+ if nested.path.is_ident("ignore") {
+ attrs.ignore = true;
+ any_attr = true;
}
- let mut any_attr = false;
- if let Meta::List(list) = meta {
- for nested in list.nested.iter() {
- if let NestedMeta::Meta(meta) = nested {
- if meta.path().is_ident("ignore") {
- attrs.ignore = true;
- any_attr = true;
- }
- if meta.path().is_ident("project") {
- if let Meta::List(list) = meta {
- if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
- attrs.project = meta.path().get_ident().cloned();
- any_attr = true;
- }
- }
- }
+ if nested.path.is_ident("project") {
+ let _ = nested.parse_nested_meta(|meta| {
+ if attrs.project.is_none() {
+ attrs.project = meta.path.get_ident().cloned();
}
- }
- }
- if !any_attr {
- panic!("error parsing stable_hasher");
+ any_attr = true;
+ Ok(())
+ });
}
+ Ok(())
+ });
+ if !any_attr {
+ panic!("error parsing stable_hasher");
}
}
attrs
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs
index 89ea89cf502..04e762e91de 100644
--- a/compiler/rustc_macros/src/newtype.rs
+++ b/compiler/rustc_macros/src/newtype.rs
@@ -25,7 +25,7 @@ impl Parse for Newtype {
let mut encodable = true;
let mut ord = true;
- attrs.retain(|attr| match attr.path.get_ident() {
+ attrs.retain(|attr| match attr.path().get_ident() {
Some(ident) => match &*ident.to_string() {
"custom_encodable" => {
encodable = false;
@@ -36,22 +36,22 @@ impl Parse for Newtype {
false
}
"max" => {
- let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
+ let Meta::NameValue(MetaNameValue { value: Expr::Lit(lit), .. }) = &attr.meta else {
panic!("#[max = NUMBER] attribute requires max value");
};
- if let Some(old) = max.replace(literal.lit) {
+ if let Some(old) = max.replace(lit.lit.clone()) {
panic!("Specified multiple max: {old:?}");
}
false
}
"debug_format" => {
- let Ok(Meta::NameValue(literal) )= attr.parse_meta() else {
+ 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(literal.lit) {
+ if let Some(old) = debug_format.replace(lit.lit.clone()) {
panic!("Specified multiple debug format options: {old:?}");
}
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 08e42a8a08f..f85ba38003c 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -15,7 +15,7 @@ mod kw {
/// Ensures only doc comment attributes are used
fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
let inner = |attr: Attribute| {
- if !attr.path.is_ident("doc") {
+ if !attr.path().is_ident("doc") {
Err(Error::new(attr.span(), "attributes not supported on queries"))
} else if attr.style != AttrStyle::Outer {
Err(Error::new(
@@ -48,7 +48,7 @@ impl Parse for Query {
let name: Ident = input.parse()?;
let arg_content;
parenthesized!(arg_content in input);
- let key = arg_content.parse()?;
+ let key = Pat::parse_single(&arg_content)?;
arg_content.parse::<Token![:]>()?;
let arg = arg_content.parse()?;
let result = input.parse()?;
@@ -158,7 +158,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
} else {
None
};
- let list = attr_content.parse_terminated(Expr::parse)?;
+ let list = attr_content.parse_terminated(Expr::parse, Token![,])?;
try_insert!(desc = (tcx, list));
} else if modifier == "cache_on_disk_if" {
// Parse a cache modifier like:
@@ -166,7 +166,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let args = if input.peek(token::Paren) {
let args;
parenthesized!(args in input);
- let tcx = args.parse()?;
+ let tcx = Pat::parse_single(&args)?;
Some(tcx)
} else {
None
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 388e254cd64..5ee4d879313 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -1,5 +1,5 @@
use quote::{quote, ToTokens};
-use syn::{parse_quote, Attribute, Meta, NestedMeta};
+use syn::parse_quote;
pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
@@ -17,21 +17,20 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
vi.construct(|_, index| {
let bind = &bindings[index];
+ let mut fixed = false;
+
// retain value of fields with #[type_foldable(identity)]
- let fixed = bind
- .ast()
- .attrs
- .iter()
- .map(Attribute::parse_meta)
- .filter_map(Result::ok)
- .flat_map(|attr| match attr {
- Meta::List(list) if list.path.is_ident("type_foldable") => list.nested,
- _ => Default::default(),
- })
- .any(|nested| match nested {
- NestedMeta::Meta(Meta::Path(path)) => path.is_ident("identity"),
- _ => false,
+ bind.ast().attrs.iter().for_each(|x| {
+ if !x.path().is_ident("type_foldable") {
+ return;
+ }
+ let _ = x.parse_nested_meta(|nested| {
+ if nested.path.is_ident("identity") {
+ fixed = true;
+ }
+ Ok(())
});
+ });
if fixed {
bind.to_token_stream()
diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs
index f6f4c4779c3..dcd505a105e 100644
--- a/compiler/rustc_macros/src/type_visitable.rs
+++ b/compiler/rustc_macros/src/type_visitable.rs
@@ -1,5 +1,5 @@
use quote::quote;
-use syn::{parse_quote, Attribute, Meta, NestedMeta};
+use syn::parse_quote;
pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
@@ -8,19 +8,21 @@ pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
// ignore fields with #[type_visitable(ignore)]
s.filter(|bi| {
- !bi.ast()
- .attrs
- .iter()
- .map(Attribute::parse_meta)
- .filter_map(Result::ok)
- .flat_map(|attr| match attr {
- Meta::List(list) if list.path.is_ident("type_visitable") => list.nested,
- _ => Default::default(),
- })
- .any(|nested| match nested {
- NestedMeta::Meta(Meta::Path(path)) => path.is_ident("ignore"),
- _ => false,
- })
+ let mut ignored = false;
+
+ bi.ast().attrs.iter().for_each(|attr| {
+ if !attr.path().is_ident("type_visitable") {
+ return;
+ }
+ let _ = attr.parse_nested_meta(|nested| {
+ if nested.path.is_ident("ignore") {
+ ignored = true;
+ }
+ Ok(())
+ });
+ });
+
+ !ignored
});
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {