Skip to content

Commit

Permalink
Auto merge of #109663 - fee1-dead-contrib:rustc_macros-syn-2.0, r=Nil…
Browse files Browse the repository at this point in the history
…strieb

migrate rustc_macros to syn 2.0

WIP at this point since I need to work on migrating the code that heavily uses `NestedMeta` for parsing. Perhaps a full refactor would be nice..
  • Loading branch information
bors committed Apr 7, 2023
2 parents c934ce9 + d764c2d commit 32ea4bb
Show file tree
Hide file tree
Showing 15 changed files with 655 additions and 694 deletions.
24 changes: 18 additions & 6 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]

[[package]]
Expand Down Expand Up @@ -4994,8 +4994,8 @@ dependencies = [
"fluent-syntax",
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"syn 2.0.8",
"synstructure 0.13.0",
"unic-langid",
]

Expand Down Expand Up @@ -6131,6 +6131,18 @@ dependencies = [
"unicode-xid",
]

[[package]]
name = "synstructure"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.8",
"unicode-xid",
]

[[package]]
name = "tar"
version = "0.4.38"
Expand Down Expand Up @@ -7154,7 +7166,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]

[[package]]
Expand All @@ -7175,7 +7187,7 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]

[[package]]
Expand Down Expand Up @@ -7204,5 +7216,5 @@ dependencies = [
"proc-macro2",
"quote",
"syn 1.0.102",
"synstructure",
"synstructure 0.12.6",
]
4 changes: 2 additions & 2 deletions compiler/rustc_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
157 changes: 67 additions & 90 deletions compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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?
Expand Down Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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"));
}

Expand Down Expand Up @@ -191,71 +188,44 @@ 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::<syn::LitStr>()?;
tokens.extend(quote! {
#diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
});
} else {
span_err(path.span().unwrap(), "unknown argument").note("only the `code` parameter is valid after the slug").emit();

// consume the buffer so we don't have syntax errors from syn
let _ = nested.parse::<TokenStream>();
}
}
Ok(())
})?;
return Ok(tokens);
}

Expand All @@ -270,7 +240,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!(),
Expand Down Expand Up @@ -309,7 +279,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 {
Expand Down Expand Up @@ -343,11 +313,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! {}),
Expand All @@ -361,7 +330,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")
})
}
Expand All @@ -378,26 +347,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); });
}
_ => (),
}
Expand Down Expand Up @@ -432,7 +409,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(...)]`")
Expand Down
Loading

0 comments on commit 32ea4bb

Please sign in to comment.