Rollup merge of #151657 - JonathanBrouwer:diag2, r=Kivooeo
Cleanup of `#[derive(Diagnostic)]` attribute parsers This PR does a lot of refactoring on the implementation of `#[derive(Diagnostic)]`. It should have no observable effect other than error messages for incorrect usage of the attributes. In general, I think the error messages got better. This PR can be reviewed commit by commit, each commit passes the tests. - [Convert parse_nested_meta to parse_args_with for #[diagnostic]](https://github.com/rust-lang/rust/pull/151657/changes/9e61014a8a0bb1f1d7911511c303a7ae2a9c2a7d) Start parsing `#[diagnostic]` using `syn`'s `parse_args_with` function instead of `parse_nested_meta`. This improves error messages and prepares for the new syntax needed for https://github.com/rust-lang/rust/issues/151366 which cannot be parsed using `parse_args_with`. - [Convert parse_nested_meta to parse_args_with for #[subdiagnostic]](https://github.com/rust-lang/rust/pull/151657/changes/5d21a21695d56b74ea249f269ee10195251008b7) Same as above but for `#[subdiagnostic]` - [Remove unused no_span option](https://github.com/rust-lang/rust/pull/151657/changes/0bf3f5d51cb853884240792818d81e70daec6ab7) Removes the `no_span` option of `#[suggestion]`, which there were no tests for and which seems to have been unused. If needed again in the future, this can be re-added pretty easily, but I find that unlikely. - [Remove HasFieldMap trait in favour of passing FieldMap directly](https://github.com/rust-lang/rust/pull/151657/changes/2e8347abf4147d2bffe4d7989a21b17ae04cdb57) Removes the `HasFieldMap` trait, because I don't really see the point of having a trait "has a field map" if we can just pass the fieldmap itself instead. r? @Kivooeo (Thanks for reviewing my PRs so far :3)
This commit is contained in:
commit
617288eb58
7 changed files with 415 additions and 505 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use syn::parse::ParseStream;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Meta, Path, Token, Type, parse_quote};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
|
@ -11,7 +12,7 @@ use crate::diagnostics::error::{
|
|||
DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
|
||||
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
|
||||
should_generate_arg, type_is_bool, type_is_unit, type_matches_path,
|
||||
};
|
||||
|
|
@ -42,19 +43,13 @@ pub(crate) struct DiagnosticDeriveVariantBuilder {
|
|||
|
||||
/// 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>,
|
||||
pub slug: Option<Path>,
|
||||
|
||||
/// Error codes are a optional part of the struct attribute - this is only set to detect
|
||||
/// multiple specifications.
|
||||
pub code: SpannedOption<()>,
|
||||
}
|
||||
|
||||
impl HasFieldMap for DiagnosticDeriveVariantBuilder {
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||
self.field_map.get(field)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticDeriveKind {
|
||||
/// 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
|
||||
|
|
@ -111,7 +106,7 @@ impl DiagnosticDeriveKind {
|
|||
|
||||
impl DiagnosticDeriveVariantBuilder {
|
||||
pub(crate) fn primary_message(&self) -> Option<&Path> {
|
||||
match self.slug.value_ref() {
|
||||
match self.slug.as_ref() {
|
||||
None => {
|
||||
span_err(self.span, "diagnostic slug not specified")
|
||||
.help(
|
||||
|
|
@ -169,7 +164,7 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
&self,
|
||||
attr: &Attribute,
|
||||
) -> Result<Option<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
|
||||
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, self)? else {
|
||||
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, &self.field_map)? else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
return Ok(None);
|
||||
|
|
@ -191,7 +186,7 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||
});
|
||||
|
||||
Ok(Some((subdiag.kind, slug, subdiag.no_span)))
|
||||
Ok(Some((subdiag.kind, slug, false)))
|
||||
}
|
||||
|
||||
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
|
||||
|
|
@ -209,47 +204,54 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
let name = attr.path().segments.last().unwrap().ident.to_string();
|
||||
let name = name.as_str();
|
||||
|
||||
let mut first = true;
|
||||
|
||||
if name == "diag" {
|
||||
let mut tokens = TokenStream::new();
|
||||
attr.parse_nested_meta(|nested| {
|
||||
let path = &nested.path;
|
||||
attr.parse_args_with(|input: ParseStream<'_>| {
|
||||
let mut input = &*input;
|
||||
let slug_recovery_point = input.fork();
|
||||
|
||||
if first && (nested.input.is_empty() || nested.input.peek(Token![,])) {
|
||||
self.slug.set_once(path.clone(), path.span().unwrap());
|
||||
first = false;
|
||||
return Ok(());
|
||||
let slug = input.parse::<Path>()?;
|
||||
if input.is_empty() || input.peek(Token![,]) {
|
||||
self.slug = Some(slug);
|
||||
} else {
|
||||
input = &slug_recovery_point;
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
let Ok(nested) = nested.value() else {
|
||||
span_err(
|
||||
nested.input.span().unwrap(),
|
||||
"diagnostic slug must be the first argument",
|
||||
)
|
||||
.emit();
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if path.is_ident("code") {
|
||||
self.code.set_once((), path.span().unwrap());
|
||||
|
||||
let code = nested.parse::<syn::Expr>()?;
|
||||
tokens.extend(quote! {
|
||||
diag.code(#code);
|
||||
});
|
||||
} else {
|
||||
span_err(path.span().unwrap(), "unknown argument")
|
||||
.note("only the `code` parameter is valid after the slug")
|
||||
while !input.is_empty() {
|
||||
input.parse::<Token![,]>()?;
|
||||
// Allow trailing comma
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
let arg_name: Path = input.parse::<Path>()?;
|
||||
if input.peek(Token![,]) {
|
||||
span_err(
|
||||
arg_name.span().unwrap(),
|
||||
"diagnostic slug must be the first argument",
|
||||
)
|
||||
.emit();
|
||||
|
||||
// consume the buffer so we don't have syntax errors from syn
|
||||
let _ = nested.parse::<TokenStream>();
|
||||
continue;
|
||||
}
|
||||
let arg_name = arg_name.require_ident()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
let arg_value = input.parse::<syn::Expr>()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"code" => {
|
||||
self.code.set_once((), arg_name.span().unwrap());
|
||||
tokens.extend(quote! {
|
||||
diag.code(#arg_value);
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
span_err(arg_name.span().unwrap(), "unknown argument")
|
||||
.note("only the `code` parameter is valid after the slug")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
return Ok(tokens);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#![deny(unused_must_use)]
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::parse::ParseStream;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Meta, MetaList, Path};
|
||||
use syn::{Attribute, Meta, MetaList, Path, Token};
|
||||
use synstructure::{BindingInfo, Structure, VariantInfo};
|
||||
|
||||
use super::utils::SubdiagnosticVariant;
|
||||
|
|
@ -11,10 +12,10 @@ use crate::diagnostics::error::{
|
|||
DiagnosticDeriveError, invalid_attr, span_err, throw_invalid_attr, throw_span_err,
|
||||
};
|
||||
use crate::diagnostics::utils::{
|
||||
AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce,
|
||||
SpannedOption, SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment,
|
||||
new_code_ident, report_error_if_not_applied_to_applicability,
|
||||
report_error_if_not_applied_to_span, should_generate_arg,
|
||||
AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption,
|
||||
SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
|
||||
report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
|
||||
should_generate_arg,
|
||||
};
|
||||
|
||||
/// The central struct for constructing the `add_to_diag` method from an annotated struct.
|
||||
|
|
@ -142,12 +143,6 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
is_enum: bool,
|
||||
}
|
||||
|
||||
impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
|
||||
self.fields.get(field)
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides frequently-needed information about the diagnostic kinds being derived for this type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KindsStatistics {
|
||||
|
|
@ -187,14 +182,12 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics {
|
|||
}
|
||||
|
||||
impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
||||
fn identify_kind(
|
||||
&mut self,
|
||||
) -> Result<Vec<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
|
||||
fn identify_kind(&mut self) -> Result<Vec<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
|
||||
let mut kind_slugs = vec![];
|
||||
|
||||
for attr in self.variant.ast().attrs {
|
||||
let Some(SubdiagnosticVariant { kind, slug, no_span }) =
|
||||
SubdiagnosticVariant::from_attr(attr, self)?
|
||||
let Some(SubdiagnosticVariant { kind, slug }) =
|
||||
SubdiagnosticVariant::from_attr(attr, &self.fields)?
|
||||
else {
|
||||
// Some attributes aren't errors - like documentation comments - but also aren't
|
||||
// subdiagnostics.
|
||||
|
|
@ -213,7 +206,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
);
|
||||
};
|
||||
|
||||
kind_slugs.push((kind, slug, no_span));
|
||||
kind_slugs.push((kind, slug));
|
||||
}
|
||||
|
||||
Ok(kind_slugs)
|
||||
|
|
@ -437,23 +430,35 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
|
||||
let mut code = None;
|
||||
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.path.is_ident("code") {
|
||||
let code_field = new_code_ident();
|
||||
let span = nested.path.span().unwrap();
|
||||
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();
|
||||
list.parse_args_with(|input: ParseStream<'_>| {
|
||||
while !input.is_empty() {
|
||||
let arg_name = input.parse::<Ident>()?;
|
||||
match arg_name.to_string().as_str() {
|
||||
"code" => {
|
||||
let code_field = new_code_ident();
|
||||
let formatting_init = build_suggestion_code(
|
||||
&code_field,
|
||||
input,
|
||||
&self.fields,
|
||||
AllowMultipleAlternatives::No,
|
||||
)?;
|
||||
code.set_once(
|
||||
(code_field, formatting_init),
|
||||
arg_name.span().unwrap(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
span_err(
|
||||
arg_name.span().unwrap(),
|
||||
"`code` is the only valid nested attribute",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
|
@ -492,8 +497,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
|
||||
let kind_slugs = self.identify_kind()?;
|
||||
|
||||
let kind_stats: KindsStatistics =
|
||||
kind_slugs.iter().map(|(kind, _slug, _no_span)| kind).collect();
|
||||
let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect();
|
||||
|
||||
let init = if kind_stats.has_multipart_suggestion {
|
||||
quote! { let mut suggestions = Vec::new(); }
|
||||
|
|
@ -526,17 +530,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
|
||||
let diag = &self.parent.diag;
|
||||
let mut calls = TokenStream::new();
|
||||
for (kind, slug, no_span) in kind_slugs {
|
||||
for (kind, slug) in kind_slugs {
|
||||
let message = format_ident!("__message");
|
||||
calls.extend(
|
||||
quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); },
|
||||
);
|
||||
|
||||
let name = format_ident!(
|
||||
"{}{}",
|
||||
if span_field.is_some() && !no_span { "span_" } else { "" },
|
||||
kind
|
||||
);
|
||||
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
|
||||
let call = match kind {
|
||||
SubdiagnosticKind::Suggestion {
|
||||
suggestion_kind,
|
||||
|
|
@ -588,9 +588,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
if let Some(span) = span_field
|
||||
&& !no_span
|
||||
{
|
||||
if let Some(span) = span_field {
|
||||
quote! { #diag.#name(#span, #message); }
|
||||
} else {
|
||||
quote! { #diag.#name(#message); }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::str::FromStr;
|
|||
use proc_macro::Span;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{ToTokens, format_ident, quote};
|
||||
use syn::meta::ParseNestedMeta;
|
||||
use syn::parse::ParseStream;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{Attribute, Field, LitStr, Meta, Path, Token, Type, TypeTuple, parenthesized};
|
||||
|
|
@ -261,108 +261,104 @@ impl<T> SetOnce<T> for SpannedOption<T> {
|
|||
|
||||
pub(super) type FieldMap = HashMap<String, TokenStream>;
|
||||
|
||||
pub(crate) trait HasFieldMap {
|
||||
/// Returns the binding for the field with the given name, if it exists on the type.
|
||||
fn get_field_binding(&self, field: &String) -> Option<&TokenStream>;
|
||||
/// In the strings in the attributes supplied to this macro, we want callers to be able to
|
||||
/// reference fields in the format string. For example:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// /// Suggest `==` when users wrote `===`.
|
||||
/// #[suggestion(slug = "parser-not-javascript-eq", code = "{lhs} == {rhs}")]
|
||||
/// struct NotJavaScriptEq {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// lhs: Ident,
|
||||
/// rhs: Ident,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We want to automatically pick up that `{lhs}` refers `self.lhs` and `{rhs}` refers to
|
||||
/// `self.rhs`, then generate this call to `format!`:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// format!("{lhs} == {rhs}", lhs = self.lhs, rhs = self.rhs)
|
||||
/// ```
|
||||
///
|
||||
/// This function builds the entire call to `format!`.
|
||||
pub(super) fn build_format(
|
||||
field_map: &FieldMap,
|
||||
input: &str,
|
||||
span: proc_macro2::Span,
|
||||
) -> TokenStream {
|
||||
// This set is used later to generate the final format string. To keep builds reproducible,
|
||||
// the iteration order needs to be deterministic, hence why we use a `BTreeSet` here
|
||||
// instead of a `HashSet`.
|
||||
let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
|
||||
|
||||
/// In the strings in the attributes supplied to this macro, we want callers to be able to
|
||||
/// reference fields in the format string. For example:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// /// Suggest `==` when users wrote `===`.
|
||||
/// #[suggestion(slug = "parser-not-javascript-eq", code = "{lhs} == {rhs}")]
|
||||
/// struct NotJavaScriptEq {
|
||||
/// #[primary_span]
|
||||
/// span: Span,
|
||||
/// lhs: Ident,
|
||||
/// rhs: Ident,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We want to automatically pick up that `{lhs}` refers `self.lhs` and `{rhs}` refers to
|
||||
/// `self.rhs`, then generate this call to `format!`:
|
||||
///
|
||||
/// ```ignore (not-usage-example)
|
||||
/// format!("{lhs} == {rhs}", lhs = self.lhs, rhs = self.rhs)
|
||||
/// ```
|
||||
///
|
||||
/// This function builds the entire call to `format!`.
|
||||
fn build_format(&self, input: &str, span: proc_macro2::Span) -> TokenStream {
|
||||
// This set is used later to generate the final format string. To keep builds reproducible,
|
||||
// the iteration order needs to be deterministic, hence why we use a `BTreeSet` here
|
||||
// instead of a `HashSet`.
|
||||
let mut referenced_fields: BTreeSet<String> = BTreeSet::new();
|
||||
// At this point, we can start parsing the format string.
|
||||
let mut it = input.chars().peekable();
|
||||
|
||||
// At this point, we can start parsing the format string.
|
||||
let mut it = input.chars().peekable();
|
||||
|
||||
// Once the start of a format string has been found, process the format string and spit out
|
||||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
||||
// the next call to `it.next()` retrieves the next character.
|
||||
while let Some(c) = it.next() {
|
||||
if c != '{' {
|
||||
continue;
|
||||
}
|
||||
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||
assert_eq!(it.next().unwrap(), '{');
|
||||
continue;
|
||||
}
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
// Once the start of a format string has been found, process the format string and spit out
|
||||
// the referenced fields. Leaves `it` sitting on the closing brace of the format string, so
|
||||
// the next call to `it.next()` retrieves the next character.
|
||||
while let Some(c) = it.next() {
|
||||
if c != '{' {
|
||||
continue;
|
||||
}
|
||||
if *it.peek().unwrap_or(&'\0') == '{' {
|
||||
assert_eq!(it.next().unwrap(), '{');
|
||||
continue;
|
||||
}
|
||||
let mut eat_argument = || -> Option<String> {
|
||||
let mut result = String::new();
|
||||
// Format specifiers look like:
|
||||
//
|
||||
// format := '{' [ argument ] [ ':' format_spec ] '}' .
|
||||
//
|
||||
// Therefore, we only need to eat until ':' or '}' to find the argument.
|
||||
while let Some(c) = it.next() {
|
||||
result.push(c);
|
||||
let next = *it.peek().unwrap_or(&'\0');
|
||||
if next == '}' {
|
||||
break;
|
||||
} else if next == ':' {
|
||||
// Eat the ':' character.
|
||||
assert_eq!(it.next().unwrap(), ':');
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Eat until (and including) the matching '}'
|
||||
while it.next()? != '}' {
|
||||
continue;
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
// At this point, `referenced_fields` contains a set of the unique fields that were
|
||||
// referenced in the format string. Generate the corresponding "x = self.x" format
|
||||
// string parameters:
|
||||
let args = referenced_fields.into_iter().map(|field: String| {
|
||||
let field_ident = format_ident!("{}", field);
|
||||
let value = match self.get_field_binding(&field) {
|
||||
Some(value) => value.clone(),
|
||||
// This field doesn't exist. Emit a diagnostic.
|
||||
None => {
|
||||
span_err(
|
||||
span.unwrap(),
|
||||
format!("`{field}` doesn't refer to a field on this type"),
|
||||
)
|
||||
if let Some(referenced_field) = eat_argument() {
|
||||
referenced_fields.insert(referenced_field);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, `referenced_fields` contains a set of the unique fields that were
|
||||
// referenced in the format string. Generate the corresponding "x = self.x" format
|
||||
// string parameters:
|
||||
let args = referenced_fields.into_iter().map(|field: String| {
|
||||
let field_ident = format_ident!("{}", field);
|
||||
let value = match field_map.get(&field) {
|
||||
Some(value) => value.clone(),
|
||||
// This field doesn't exist. Emit a diagnostic.
|
||||
None => {
|
||||
span_err(span.unwrap(), format!("`{field}` doesn't refer to a field on this type"))
|
||||
.emit();
|
||||
quote! {
|
||||
"{#field}"
|
||||
}
|
||||
quote! {
|
||||
"{#field}"
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
#field_ident = #value
|
||||
}
|
||||
});
|
||||
};
|
||||
quote! {
|
||||
format!(#input #(,#args)*)
|
||||
#field_ident = #value
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
format!(#input #(,#args)*)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,76 +424,63 @@ pub(super) enum AllowMultipleAlternatives {
|
|||
}
|
||||
|
||||
fn parse_suggestion_values(
|
||||
nested: ParseNestedMeta<'_>,
|
||||
nested: ParseStream<'_>,
|
||||
allow_multiple: AllowMultipleAlternatives,
|
||||
) -> syn::Result<Vec<LitStr>> {
|
||||
let values = if let Ok(val) = nested.value() {
|
||||
vec![val.parse()?]
|
||||
} else {
|
||||
let content;
|
||||
parenthesized!(content in nested.input);
|
||||
if nested.parse::<Token![=]>().is_ok() {
|
||||
return Ok(vec![nested.parse::<LitStr>()?]);
|
||||
}
|
||||
|
||||
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||
let content;
|
||||
parenthesized!(content in nested);
|
||||
if let AllowMultipleAlternatives::No = allow_multiple {
|
||||
span_err(content.span().unwrap(), "expected exactly one string literal for `code = ...`")
|
||||
.emit();
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let literals = Punctuated::<LitStr, Token![,]>::parse_terminated(&content);
|
||||
Ok(match literals {
|
||||
Ok(p) if p.is_empty() => {
|
||||
span_err(
|
||||
nested.input.span().unwrap(),
|
||||
"expected exactly one string literal for `code = ...`",
|
||||
content.span().unwrap(),
|
||||
"expected at least one string literal for `code(...)`",
|
||||
)
|
||||
.emit();
|
||||
vec![]
|
||||
} else {
|
||||
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![]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(values)
|
||||
Ok(p) => p.into_iter().collect(),
|
||||
Err(_) => {
|
||||
span_err(content.span().unwrap(), "`code(...)` must contain only string literals")
|
||||
.emit();
|
||||
vec![]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs the `format!()` invocation(s) necessary for a `#[suggestion*(code = "foo")]` or
|
||||
/// `#[suggestion*(code("foo", "bar"))]` attribute field
|
||||
pub(super) fn build_suggestion_code(
|
||||
code_field: &Ident,
|
||||
nested: ParseNestedMeta<'_>,
|
||||
fields: &impl HasFieldMap,
|
||||
nested: ParseStream<'_>,
|
||||
fields: &FieldMap,
|
||||
allow_multiple: AllowMultipleAlternatives,
|
||||
) -> TokenStream {
|
||||
let values = match parse_suggestion_values(nested, allow_multiple) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
) -> Result<TokenStream, syn::Error> {
|
||||
let values = parse_suggestion_values(nested, allow_multiple)?;
|
||||
|
||||
if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||
Ok(if let AllowMultipleAlternatives::Yes = allow_multiple {
|
||||
let formatted_strings: Vec<_> = values
|
||||
.into_iter()
|
||||
.map(|value| fields.build_format(&value.value(), value.span()))
|
||||
.map(|value| build_format(fields, &value.value(), value.span()))
|
||||
.collect();
|
||||
quote! { let #code_field = [#(#formatted_strings),*].into_iter(); }
|
||||
} else if let [value] = values.as_slice() {
|
||||
let formatted_str = fields.build_format(&value.value(), value.span());
|
||||
let formatted_str = build_format(fields, &value.value(), value.span());
|
||||
quote! { let #code_field = #formatted_str; }
|
||||
} else {
|
||||
// error handled previously
|
||||
quote! { let #code_field = String::new(); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Possible styles for suggestion subdiagnostics.
|
||||
|
|
@ -605,16 +588,15 @@ pub(super) enum SubdiagnosticKind {
|
|||
pub(super) struct SubdiagnosticVariant {
|
||||
pub(super) kind: SubdiagnosticKind,
|
||||
pub(super) slug: Option<Path>,
|
||||
pub(super) no_span: bool,
|
||||
}
|
||||
|
||||
impl SubdiagnosticVariant {
|
||||
/// Constructs a `SubdiagnosticVariant` from a field or type attribute such as `#[note]`,
|
||||
/// `#[error(parser::add_paren, no_span)]` or `#[suggestion(code = "...")]`. Returns the
|
||||
/// `#[error(parser::add_paren)]` or `#[suggestion(code = "...")]`. Returns the
|
||||
/// `SubdiagnosticKind` and the diagnostic slug, if specified.
|
||||
pub(super) fn from_attr(
|
||||
attr: &Attribute,
|
||||
fields: &impl HasFieldMap,
|
||||
fields: &FieldMap,
|
||||
) -> Result<Option<SubdiagnosticVariant>, DiagnosticDeriveError> {
|
||||
// Always allow documentation comments.
|
||||
if is_doc_comment(attr) {
|
||||
|
|
@ -694,7 +676,7 @@ impl SubdiagnosticVariant {
|
|||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||
return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
|
||||
return Ok(Some(SubdiagnosticVariant { kind, slug: None }));
|
||||
}
|
||||
SubdiagnosticKind::Suggestion { .. } => {
|
||||
throw_span_err!(span, "suggestion without `code = \"...\"`")
|
||||
|
|
@ -709,112 +691,93 @@ impl SubdiagnosticVariant {
|
|||
let mut code = None;
|
||||
let mut suggestion_kind = None;
|
||||
|
||||
let mut first = true;
|
||||
let mut slug = None;
|
||||
let mut no_span = false;
|
||||
|
||||
list.parse_nested_meta(|nested| {
|
||||
if nested.input.is_empty() || nested.input.peek(Token![,]) {
|
||||
if first {
|
||||
slug = Some(nested.path);
|
||||
} else if nested.path.is_ident("no_span") {
|
||||
no_span = true;
|
||||
} else {
|
||||
span_err(nested.input.span().unwrap(), "a diagnostic slug must be the first argument to the attribute").emit();
|
||||
list.parse_args_with(|input: ParseStream<'_>| {
|
||||
let mut is_first = true;
|
||||
while !input.is_empty() {
|
||||
let arg_name: Path = input.parse::<Path>()?;
|
||||
let arg_name_span = arg_name.span().unwrap();
|
||||
if input.is_empty() || input.parse::<Token![,]>().is_ok() {
|
||||
if is_first {
|
||||
slug = Some(arg_name);
|
||||
is_first = false;
|
||||
} else {
|
||||
span_err(arg_name_span, "a diagnostic slug must be the first argument to the attribute").emit();
|
||||
}
|
||||
continue
|
||||
}
|
||||
is_first = false;
|
||||
|
||||
first = false;
|
||||
return Ok(());
|
||||
}
|
||||
match (arg_name.require_ident()?.to_string().as_str(), &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let code_init = build_suggestion_code(
|
||||
&code_field,
|
||||
&input,
|
||||
fields,
|
||||
AllowMultipleAlternatives::Yes,
|
||||
)?;
|
||||
code.set_once(code_init, arg_name_span);
|
||||
}
|
||||
(
|
||||
"applicability",
|
||||
SubdiagnosticKind::Suggestion { applicability, .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { applicability, .. },
|
||||
) => {
|
||||
input.parse::<Token![=]>()?;
|
||||
let value = input.parse::<LitStr>()?;
|
||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid applicability").emit();
|
||||
Applicability::Unspecified
|
||||
});
|
||||
applicability.set_once(value, span);
|
||||
}
|
||||
(
|
||||
"style",
|
||||
SubdiagnosticKind::Suggestion { .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. },
|
||||
) => {
|
||||
input.parse::<Token![=]>()?;
|
||||
let value = input.parse::<LitStr>()?;
|
||||
|
||||
first = false;
|
||||
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
|
||||
});
|
||||
|
||||
let nested_name = nested.path.segments.last().unwrap().ident.to_string();
|
||||
let nested_name = nested_name.as_str();
|
||||
suggestion_kind.set_once(value, span);
|
||||
}
|
||||
|
||||
let path_span = nested.path.span().unwrap();
|
||||
let val_span = nested.input.span().unwrap();
|
||||
|
||||
macro_rules! get_string {
|
||||
() => {{
|
||||
let Ok(value) = nested.value().and_then(|x| x.parse::<LitStr>()) else {
|
||||
span_err(val_span, "expected `= \"xxx\"`").emit();
|
||||
return Ok(());
|
||||
};
|
||||
value
|
||||
}};
|
||||
}
|
||||
|
||||
let mut has_errors = false;
|
||||
let input = nested.input;
|
||||
|
||||
match (nested_name, &mut kind) {
|
||||
("code", SubdiagnosticKind::Suggestion { code_field, .. }) => {
|
||||
let code_init = build_suggestion_code(
|
||||
code_field,
|
||||
nested,
|
||||
fields,
|
||||
AllowMultipleAlternatives::Yes,
|
||||
);
|
||||
code.set_once(code_init, path_span);
|
||||
}
|
||||
(
|
||||
"applicability",
|
||||
SubdiagnosticKind::Suggestion { applicability, .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { applicability, .. },
|
||||
) => {
|
||||
let value = get_string!();
|
||||
let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| {
|
||||
span_err(value.span().unwrap(), "invalid applicability").emit();
|
||||
has_errors = true;
|
||||
Applicability::Unspecified
|
||||
});
|
||||
applicability.set_once(value, span);
|
||||
}
|
||||
(
|
||||
"style",
|
||||
SubdiagnosticKind::Suggestion { .. }
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. },
|
||||
) => {
|
||||
let value = get_string!();
|
||||
|
||||
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`")
|
||||
// Invalid nested attribute
|
||||
(_, SubdiagnosticKind::Suggestion { .. }) => {
|
||||
span_err(arg_name_span, "invalid nested attribute")
|
||||
.help(
|
||||
"only `style`, `code` and `applicability` are valid nested attributes",
|
||||
)
|
||||
.emit();
|
||||
has_errors = true;
|
||||
SuggestionKind::Normal
|
||||
});
|
||||
|
||||
suggestion_kind.set_once(value, span);
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
|
||||
span_err(arg_name_span, "invalid nested attribute")
|
||||
.help("only `style` and `applicability` are valid nested attributes")
|
||||
.emit();
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
_ => {
|
||||
span_err(arg_name_span, "no nested attribute expected here").emit();
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid nested attribute
|
||||
(_, SubdiagnosticKind::Suggestion { .. }) => {
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help(
|
||||
"only `no_span`, `style`, `code` and `applicability` are valid nested attributes",
|
||||
)
|
||||
.emit();
|
||||
has_errors = true;
|
||||
}
|
||||
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
|
||||
span_err(path_span, "invalid nested attribute")
|
||||
.help("only `no_span`, `style` and `applicability` are valid nested attributes")
|
||||
.emit();
|
||||
has_errors = true;
|
||||
}
|
||||
_ => {
|
||||
span_err(path_span, "only `no_span` is a valid nested attribute").emit();
|
||||
has_errors = true;
|
||||
}
|
||||
if input.is_empty() { break }
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
|
||||
if has_errors {
|
||||
// Consume the rest of the input to avoid spamming errors
|
||||
let _ = input.parse::<TokenStream>();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
|
@ -851,7 +814,7 @@ impl SubdiagnosticVariant {
|
|||
| SubdiagnosticKind::Warn => {}
|
||||
}
|
||||
|
||||
Ok(Some(SubdiagnosticVariant { kind, slug, no_span }))
|
||||
Ok(Some(SubdiagnosticVariant { kind, slug }))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,20 +80,17 @@ struct InvalidNestedStructAttr {}
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(nonsense("foo"), code = E0123, slug = "foo")]
|
||||
//~^ ERROR diagnostic slug must be the first argument
|
||||
//~| ERROR diagnostic slug not specified
|
||||
//~^ ERROR derive(Diagnostic): diagnostic slug not specified
|
||||
struct InvalidNestedStructAttr1 {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(nonsense = "...", code = E0123, slug = "foo")]
|
||||
//~^ ERROR unknown argument
|
||||
//~| ERROR diagnostic slug not specified
|
||||
//~^ ERROR diagnostic slug not specified
|
||||
struct InvalidNestedStructAttr2 {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(nonsense = 4, code = E0123, slug = "foo")]
|
||||
//~^ ERROR unknown argument
|
||||
//~| ERROR diagnostic slug not specified
|
||||
//~^ ERROR diagnostic slug not specified
|
||||
struct InvalidNestedStructAttr3 {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -113,7 +110,6 @@ struct WrongPlaceField {
|
|||
#[diag(no_crate_example, code = E0123)]
|
||||
#[diag(no_crate_example, code = E0456)]
|
||||
//~^ ERROR specified multiple times
|
||||
//~^^ ERROR specified multiple times
|
||||
struct DiagSpecifiedTwice {}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -543,7 +539,7 @@ struct LabelWithTrailingPath {
|
|||
#[diag(no_crate_example, code = E0123)]
|
||||
struct LabelWithTrailingNameValue {
|
||||
#[label(no_crate_label, foo = "...")]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -551,7 +547,7 @@ struct LabelWithTrailingNameValue {
|
|||
#[diag(no_crate_example, code = E0123)]
|
||||
struct LabelWithTrailingList {
|
||||
#[label(no_crate_label, foo("..."))]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -807,7 +803,7 @@ struct SuggestionsInvalidItem {
|
|||
sub: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)] //~ ERROR cannot find value `__code_34` in this scope
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(no_crate_example)]
|
||||
struct SuggestionsInvalidLiteral {
|
||||
#[suggestion(code = 3)]
|
||||
|
|
|
|||
|
|
@ -48,12 +48,6 @@ LL | #[diag(code = E0123)]
|
|||
|
|
||||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug must be the first argument
|
||||
--> $DIR/diagnostic-derive.rs:82:16
|
||||
|
|
||||
LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:82:1
|
||||
|
|
||||
|
|
@ -62,32 +56,16 @@ LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
|
|||
|
|
||||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): unknown argument
|
||||
--> $DIR/diagnostic-derive.rs:88:8
|
||||
|
|
||||
LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: only the `code` parameter is valid after the slug
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:88:1
|
||||
--> $DIR/diagnostic-derive.rs:87:1
|
||||
|
|
||||
LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
|
||||
| ^
|
||||
|
|
||||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): unknown argument
|
||||
--> $DIR/diagnostic-derive.rs:94:8
|
||||
|
|
||||
LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: only the `code` parameter is valid after the slug
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:94:1
|
||||
--> $DIR/diagnostic-derive.rs:92:1
|
||||
|
|
||||
LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
|
||||
| ^
|
||||
|
|
@ -95,7 +73,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): unknown argument
|
||||
--> $DIR/diagnostic-derive.rs:100:40
|
||||
--> $DIR/diagnostic-derive.rs:97:40
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
|
||||
| ^^^^
|
||||
|
|
@ -103,55 +81,43 @@ LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
|
|||
= note: only the `code` parameter is valid after the slug
|
||||
|
||||
error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:107:5
|
||||
--> $DIR/diagnostic-derive.rs:104:5
|
||||
|
|
||||
LL | #[suggestion = "bar"]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:114:8
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0456)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:113:8
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0123)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:114:26
|
||||
--> $DIR/diagnostic-derive.rs:111:26
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0456)]
|
||||
| ^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:113:26
|
||||
--> $DIR/diagnostic-derive.rs:110:26
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0123)]
|
||||
| ^^^^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:120:40
|
||||
--> $DIR/diagnostic-derive.rs:116:40
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0123, code = E0456)]
|
||||
| ^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:120:26
|
||||
--> $DIR/diagnostic-derive.rs:116:26
|
||||
|
|
||||
LL | #[diag(no_crate_example, code = E0123, code = E0456)]
|
||||
| ^^^^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug must be the first argument
|
||||
--> $DIR/diagnostic-derive.rs:125:43
|
||||
--> $DIR/diagnostic-derive.rs:121:26
|
||||
|
|
||||
LL | #[diag(no_crate_example, no_crate::example, code = E0123)]
|
||||
| ^
|
||||
| ^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:130:1
|
||||
--> $DIR/diagnostic-derive.rs:126:1
|
||||
|
|
||||
LL | struct KindNotProvided {}
|
||||
| ^^^^^^
|
||||
|
|
@ -159,7 +125,7 @@ LL | struct KindNotProvided {}
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:133:1
|
||||
--> $DIR/diagnostic-derive.rs:129:1
|
||||
|
|
||||
LL | #[diag(code = E0123)]
|
||||
| ^
|
||||
|
|
@ -167,31 +133,31 @@ LL | #[diag(code = E0123)]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:144:5
|
||||
--> $DIR/diagnostic-derive.rs:140:5
|
||||
|
|
||||
LL | #[primary_span]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[nonsense]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:152:5
|
||||
--> $DIR/diagnostic-derive.rs:148:5
|
||||
|
|
||||
LL | #[nonsense]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:169:5
|
||||
--> $DIR/diagnostic-derive.rs:165:5
|
||||
|
|
||||
LL | #[label(no_crate_label)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `name` doesn't refer to a field on this type
|
||||
--> $DIR/diagnostic-derive.rs:177:46
|
||||
--> $DIR/diagnostic-derive.rs:173:46
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "{name}")]
|
||||
| ^^^^^^^^
|
||||
|
||||
error: invalid format string: expected `}` but string was terminated
|
||||
--> $DIR/diagnostic-derive.rs:182:10
|
||||
--> $DIR/diagnostic-derive.rs:178:10
|
||||
|
|
||||
LL | #[derive(Diagnostic)]
|
||||
| ^^^^^^^^^^ expected `}` in format string
|
||||
|
|
@ -200,7 +166,7 @@ LL | #[derive(Diagnostic)]
|
|||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid format string: unmatched `}` found
|
||||
--> $DIR/diagnostic-derive.rs:192:10
|
||||
--> $DIR/diagnostic-derive.rs:188:10
|
||||
|
|
||||
LL | #[derive(Diagnostic)]
|
||||
| ^^^^^^^^^^ unmatched `}` in format string
|
||||
|
|
@ -209,47 +175,47 @@ LL | #[derive(Diagnostic)]
|
|||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
|
||||
--> $DIR/diagnostic-derive.rs:212:5
|
||||
--> $DIR/diagnostic-derive.rs:208:5
|
||||
|
|
||||
LL | #[label(no_crate_label)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): suggestion without `code = "..."`
|
||||
--> $DIR/diagnostic-derive.rs:231:5
|
||||
--> $DIR/diagnostic-derive.rs:227:5
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): invalid nested attribute
|
||||
--> $DIR/diagnostic-derive.rs:239:18
|
||||
--> $DIR/diagnostic-derive.rs:235:18
|
||||
|
|
||||
LL | #[suggestion(nonsense = "bar")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
|
||||
= help: only `style`, `code` and `applicability` are valid nested attributes
|
||||
|
||||
error: derive(Diagnostic): suggestion without `code = "..."`
|
||||
--> $DIR/diagnostic-derive.rs:239:5
|
||||
--> $DIR/diagnostic-derive.rs:235:5
|
||||
|
|
||||
LL | #[suggestion(nonsense = "bar")]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): invalid nested attribute
|
||||
--> $DIR/diagnostic-derive.rs:248:18
|
||||
--> $DIR/diagnostic-derive.rs:244:18
|
||||
|
|
||||
LL | #[suggestion(msg = "bar")]
|
||||
| ^^^
|
||||
|
|
||||
= help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
|
||||
= help: only `style`, `code` and `applicability` are valid nested attributes
|
||||
|
||||
error: derive(Diagnostic): suggestion without `code = "..."`
|
||||
--> $DIR/diagnostic-derive.rs:248:5
|
||||
--> $DIR/diagnostic-derive.rs:244:5
|
||||
|
|
||||
LL | #[suggestion(msg = "bar")]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): wrong field type for suggestion
|
||||
--> $DIR/diagnostic-derive.rs:271:5
|
||||
--> $DIR/diagnostic-derive.rs:267:5
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")]
|
||||
| ^
|
||||
|
|
@ -257,79 +223,79 @@ LL | #[suggestion(no_crate_suggestion, code = "This is suggested code")]
|
|||
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:287:24
|
||||
--> $DIR/diagnostic-derive.rs:283:24
|
||||
|
|
||||
LL | suggestion: (Span, Span, Applicability),
|
||||
| ^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:287:18
|
||||
--> $DIR/diagnostic-derive.rs:283:18
|
||||
|
|
||||
LL | suggestion: (Span, Span, Applicability),
|
||||
| ^^^^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:295:33
|
||||
--> $DIR/diagnostic-derive.rs:291:33
|
||||
|
|
||||
LL | suggestion: (Applicability, Applicability, Span),
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:295:18
|
||||
--> $DIR/diagnostic-derive.rs:291:18
|
||||
|
|
||||
LL | suggestion: (Applicability, Applicability, Span),
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:302:5
|
||||
--> $DIR/diagnostic-derive.rs:298:5
|
||||
|
|
||||
LL | #[label = "bar"]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:453:5
|
||||
--> $DIR/diagnostic-derive.rs:449:5
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
|
||||
| ^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:455:24
|
||||
--> $DIR/diagnostic-derive.rs:451:24
|
||||
|
|
||||
LL | suggestion: (Span, Applicability),
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): invalid applicability
|
||||
--> $DIR/diagnostic-derive.rs:461:69
|
||||
--> $DIR/diagnostic-derive.rs:457:69
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
|
||||
| ^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
|
||||
--> $DIR/diagnostic-derive.rs:528:5
|
||||
--> $DIR/diagnostic-derive.rs:524:5
|
||||
|
|
||||
LL | #[help(no_crate_help)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
|
||||
--> $DIR/diagnostic-derive.rs:537:32
|
||||
--> $DIR/diagnostic-derive.rs:533:29
|
||||
|
|
||||
LL | #[label(no_crate_label, foo)]
|
||||
| ^
|
||||
| ^^^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
--> $DIR/diagnostic-derive.rs:545:29
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/diagnostic-derive.rs:541:29
|
||||
|
|
||||
LL | #[label(no_crate_label, foo = "...")]
|
||||
| ^^^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
--> $DIR/diagnostic-derive.rs:553:29
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/diagnostic-derive.rs:549:29
|
||||
|
|
||||
LL | #[label(no_crate_label, foo("..."))]
|
||||
| ^^^
|
||||
|
||||
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:565:5
|
||||
--> $DIR/diagnostic-derive.rs:561:5
|
||||
|
|
||||
LL | #[primary_span]
|
||||
| ^
|
||||
|
|
@ -337,13 +303,13 @@ LL | #[primary_span]
|
|||
= help: the `primary_span` field attribute is not valid for lint diagnostics
|
||||
|
||||
error: derive(Diagnostic): `#[error(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:585:1
|
||||
--> $DIR/diagnostic-derive.rs:581:1
|
||||
|
|
||||
LL | #[error(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:585:1
|
||||
--> $DIR/diagnostic-derive.rs:581:1
|
||||
|
|
||||
LL | #[error(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
|
@ -351,13 +317,13 @@ LL | #[error(no_crate_example, code = E0123)]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:592:1
|
||||
--> $DIR/diagnostic-derive.rs:588:1
|
||||
|
|
||||
LL | #[warn_(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:592:1
|
||||
--> $DIR/diagnostic-derive.rs:588:1
|
||||
|
|
||||
LL | #[warn_(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
|
@ -365,13 +331,13 @@ LL | #[warn_(no_crate_example, code = E0123)]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:599:1
|
||||
--> $DIR/diagnostic-derive.rs:595:1
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:599:1
|
||||
--> $DIR/diagnostic-derive.rs:595:1
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
|
@ -379,13 +345,13 @@ LL | #[lint(no_crate_example, code = E0123)]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:606:1
|
||||
--> $DIR/diagnostic-derive.rs:602:1
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): diagnostic slug not specified
|
||||
--> $DIR/diagnostic-derive.rs:606:1
|
||||
--> $DIR/diagnostic-derive.rs:602:1
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^
|
||||
|
|
@ -393,19 +359,19 @@ LL | #[lint(no_crate_example, code = E0123)]
|
|||
= help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/diagnostic-derive.rs:615:53
|
||||
--> $DIR/diagnostic-derive.rs:611:53
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
|
||||
| ^^^^
|
||||
|
|
||||
note: previously specified here
|
||||
--> $DIR/diagnostic-derive.rs:615:39
|
||||
--> $DIR/diagnostic-derive.rs:611:39
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
|
||||
| ^^^^
|
||||
|
||||
error: derive(Diagnostic): wrong types for suggestion
|
||||
--> $DIR/diagnostic-derive.rs:624:24
|
||||
--> $DIR/diagnostic-derive.rs:620:24
|
||||
|
|
||||
LL | suggestion: (Span, usize),
|
||||
| ^^^^^
|
||||
|
|
@ -413,7 +379,7 @@ LL | suggestion: (Span, usize),
|
|||
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
|
||||
|
||||
error: derive(Diagnostic): wrong types for suggestion
|
||||
--> $DIR/diagnostic-derive.rs:632:17
|
||||
--> $DIR/diagnostic-derive.rs:628:17
|
||||
|
|
||||
LL | suggestion: (Span,),
|
||||
| ^^^^^^^
|
||||
|
|
@ -421,13 +387,13 @@ LL | suggestion: (Span,),
|
|||
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
|
||||
|
||||
error: derive(Diagnostic): suggestion without `code = "..."`
|
||||
--> $DIR/diagnostic-derive.rs:639:5
|
||||
--> $DIR/diagnostic-derive.rs:635:5
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:646:1
|
||||
--> $DIR/diagnostic-derive.rs:642:1
|
||||
|
|
||||
LL | #[multipart_suggestion(no_crate_suggestion)]
|
||||
| ^
|
||||
|
|
@ -435,7 +401,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)]
|
|||
= help: consider creating a `Subdiagnostic` instead
|
||||
|
||||
error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:649:1
|
||||
--> $DIR/diagnostic-derive.rs:645:1
|
||||
|
|
||||
LL | #[multipart_suggestion()]
|
||||
| ^
|
||||
|
|
@ -443,7 +409,7 @@ LL | #[multipart_suggestion()]
|
|||
= help: consider creating a `Subdiagnostic` instead
|
||||
|
||||
error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:653:5
|
||||
--> $DIR/diagnostic-derive.rs:649:5
|
||||
|
|
||||
LL | #[multipart_suggestion(no_crate_suggestion)]
|
||||
| ^
|
||||
|
|
@ -451,7 +417,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)]
|
|||
= help: consider creating a `Subdiagnostic` instead
|
||||
|
||||
error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:661:1
|
||||
--> $DIR/diagnostic-derive.rs:657:1
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "...")]
|
||||
| ^
|
||||
|
|
@ -459,7 +425,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")]
|
|||
= help: `#[label]` and `#[suggestion]` can only be applied to fields
|
||||
|
||||
error: derive(Diagnostic): `#[label]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:670:1
|
||||
--> $DIR/diagnostic-derive.rs:666:1
|
||||
|
|
||||
LL | #[label]
|
||||
| ^
|
||||
|
|
@ -467,73 +433,73 @@ LL | #[label]
|
|||
= help: `#[label]` and `#[suggestion]` can only be applied to fields
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:704:5
|
||||
--> $DIR/diagnostic-derive.rs:700:5
|
||||
|
|
||||
LL | #[subdiagnostic(bad)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:712:5
|
||||
--> $DIR/diagnostic-derive.rs:708:5
|
||||
|
|
||||
LL | #[subdiagnostic = "bad"]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:720:5
|
||||
--> $DIR/diagnostic-derive.rs:716:5
|
||||
|
|
||||
LL | #[subdiagnostic(bad, bad)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:728:5
|
||||
--> $DIR/diagnostic-derive.rs:724:5
|
||||
|
|
||||
LL | #[subdiagnostic("bad")]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:736:5
|
||||
--> $DIR/diagnostic-derive.rs:732:5
|
||||
|
|
||||
LL | #[subdiagnostic(eager)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:744:5
|
||||
--> $DIR/diagnostic-derive.rs:740:5
|
||||
|
|
||||
LL | #[subdiagnostic(eager)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:765:5
|
||||
--> $DIR/diagnostic-derive.rs:761:5
|
||||
|
|
||||
LL | #[subdiagnostic(eager)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): expected at least one string literal for `code(...)`
|
||||
--> $DIR/diagnostic-derive.rs:796:23
|
||||
--> $DIR/diagnostic-derive.rs:792:23
|
||||
|
|
||||
LL | #[suggestion(code())]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `code(...)` must contain only string literals
|
||||
--> $DIR/diagnostic-derive.rs:804:23
|
||||
--> $DIR/diagnostic-derive.rs:800:23
|
||||
|
|
||||
LL | #[suggestion(code(foo))]
|
||||
| ^^^
|
||||
|
||||
error: unexpected token, expected `)`
|
||||
--> $DIR/diagnostic-derive.rs:804:23
|
||||
--> $DIR/diagnostic-derive.rs:800:23
|
||||
|
|
||||
LL | #[suggestion(code(foo))]
|
||||
| ^^^
|
||||
|
||||
error: expected string literal
|
||||
--> $DIR/diagnostic-derive.rs:813:25
|
||||
--> $DIR/diagnostic-derive.rs:809:25
|
||||
|
|
||||
LL | #[suggestion(code = 3)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
|
||||
--> $DIR/diagnostic-derive.rs:828:5
|
||||
--> $DIR/diagnostic-derive.rs:824:5
|
||||
|
|
||||
LL | #[suggestion(no_crate_suggestion, code = "")]
|
||||
| ^
|
||||
|
|
@ -549,13 +515,13 @@ LL | #[nonsense(no_crate_example, code = E0123)]
|
|||
| ^^^^^^^^
|
||||
|
||||
error: cannot find attribute `nonsense` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:152:7
|
||||
--> $DIR/diagnostic-derive.rs:148:7
|
||||
|
|
||||
LL | #[nonsense]
|
||||
| ^^^^^^^^
|
||||
|
||||
error: cannot find attribute `error` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:585:3
|
||||
--> $DIR/diagnostic-derive.rs:581:3
|
||||
|
|
||||
LL | #[error(no_crate_example, code = E0123)]
|
||||
| ^^^^^
|
||||
|
|
@ -567,7 +533,7 @@ LL | struct ErrorAttribute {}
|
|||
|
|
||||
|
||||
error: cannot find attribute `warn_` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:592:3
|
||||
--> $DIR/diagnostic-derive.rs:588:3
|
||||
|
|
||||
LL | #[warn_(no_crate_example, code = E0123)]
|
||||
| ^^^^^
|
||||
|
|
@ -579,7 +545,7 @@ LL + #[warn(no_crate_example, code = E0123)]
|
|||
|
|
||||
|
||||
error: cannot find attribute `lint` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:599:3
|
||||
--> $DIR/diagnostic-derive.rs:595:3
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^^^^
|
||||
|
|
@ -591,7 +557,7 @@ LL + #[link(no_crate_example, code = E0123)]
|
|||
|
|
||||
|
||||
error: cannot find attribute `lint` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:606:3
|
||||
--> $DIR/diagnostic-derive.rs:602:3
|
||||
|
|
||||
LL | #[lint(no_crate_example, code = E0123)]
|
||||
| ^^^^
|
||||
|
|
@ -603,7 +569,7 @@ LL + #[link(no_crate_example, code = E0123)]
|
|||
|
|
||||
|
||||
error: cannot find attribute `multipart_suggestion` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:646:3
|
||||
--> $DIR/diagnostic-derive.rs:642:3
|
||||
|
|
||||
LL | #[multipart_suggestion(no_crate_suggestion)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -615,7 +581,7 @@ LL | struct MultipartSuggestion {
|
|||
|
|
||||
|
||||
error: cannot find attribute `multipart_suggestion` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:649:3
|
||||
--> $DIR/diagnostic-derive.rs:645:3
|
||||
|
|
||||
LL | #[multipart_suggestion()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -627,7 +593,7 @@ LL | struct MultipartSuggestion {
|
|||
|
|
||||
|
||||
error: cannot find attribute `multipart_suggestion` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:653:7
|
||||
--> $DIR/diagnostic-derive.rs:649:7
|
||||
|
|
||||
LL | #[multipart_suggestion(no_crate_suggestion)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -640,16 +606,8 @@ error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
|
|||
LL | #[diag(nonsense, code = E0123)]
|
||||
| ^^^^^^^^ not found in `crate::fluent_generated`
|
||||
|
||||
error[E0425]: cannot find value `__code_34` in this scope
|
||||
--> $DIR/diagnostic-derive.rs:810:10
|
||||
|
|
||||
LL | #[derive(Diagnostic)]
|
||||
| ^^^^^^^^^^ not found in this scope
|
||||
|
|
||||
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `Hello: IntoDiagArg` is not satisfied
|
||||
--> $DIR/diagnostic-derive.rs:351:12
|
||||
--> $DIR/diagnostic-derive.rs:347:12
|
||||
|
|
||||
LL | #[derive(Diagnostic)]
|
||||
| ---------- required by a bound introduced by this call
|
||||
|
|
@ -670,7 +628,7 @@ note: required by a bound in `Diag::<'a, G>::arg`
|
|||
= note: in this macro invocation
|
||||
= note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 85 previous errors
|
||||
error: aborting due to 80 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0425.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ struct F {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(bug = "...")]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
//~| ERROR diagnostic slug must be first argument
|
||||
struct G {
|
||||
#[primary_span]
|
||||
|
|
@ -95,7 +95,7 @@ struct G {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label("...")]
|
||||
//~^ ERROR unexpected literal in nested attribute, expected ident
|
||||
//~^ ERROR expected identifier
|
||||
struct H {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -104,7 +104,7 @@ struct H {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(slug = 4)]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
//~| ERROR diagnostic slug must be first argument
|
||||
struct J {
|
||||
#[primary_span]
|
||||
|
|
@ -114,7 +114,7 @@ struct J {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(slug("..."))]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
//~| ERROR diagnostic slug must be first argument
|
||||
struct K {
|
||||
#[primary_span]
|
||||
|
|
@ -133,7 +133,7 @@ struct M {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(no_crate_example, code = "...")]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
struct N {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -142,7 +142,7 @@ struct N {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(no_crate_example, applicability = "machine-applicable")]
|
||||
//~^ ERROR only `no_span` is a valid nested attribute
|
||||
//~^ ERROR no nested attribute expected here
|
||||
struct O {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -214,7 +214,7 @@ enum T {
|
|||
enum U {
|
||||
#[label(code = "...")]
|
||||
//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
|
||||
//~| ERROR only `no_span` is a valid nested attribute
|
||||
//~| ERROR no nested attribute expected here
|
||||
A {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -775,7 +775,7 @@ struct SuggestionStyleInvalid1 {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(no_crate_example, code = "", style = 42)]
|
||||
//~^ ERROR expected `= "xxx"`
|
||||
//~^ ERROR expected string literal
|
||||
struct SuggestionStyleInvalid2 {
|
||||
#[primary_span]
|
||||
sub: Span,
|
||||
|
|
@ -791,8 +791,7 @@ struct SuggestionStyleInvalid3 {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(no_crate_example, code = "", style("foo"))]
|
||||
//~^ ERROR expected `= "xxx"`
|
||||
//~| ERROR expected `,`
|
||||
//~^ ERROR expected `=`
|
||||
struct SuggestionStyleInvalid4 {
|
||||
#[primary_span]
|
||||
sub: Span,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
|
|||
LL | #[label = "..."]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:87:9
|
||||
|
|
||||
LL | #[label(bug = "...")]
|
||||
|
|
@ -34,13 +34,13 @@ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(
|
|||
LL | #[label(bug = "...")]
|
||||
| ^
|
||||
|
||||
error: unexpected literal in nested attribute, expected ident
|
||||
error: expected identifier
|
||||
--> $DIR/subdiagnostic-derive.rs:97:9
|
||||
|
|
||||
LL | #[label("...")]
|
||||
| ^^^^^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:106:9
|
||||
|
|
||||
LL | #[label(slug = 4)]
|
||||
|
|
@ -52,7 +52,7 @@ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(
|
|||
LL | #[label(slug = 4)]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:116:9
|
||||
|
|
||||
LL | #[label(slug("..."))]
|
||||
|
|
@ -70,13 +70,13 @@ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(
|
|||
LL | #[label()]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:135:27
|
||||
|
|
||||
LL | #[label(no_crate_example, code = "...")]
|
||||
| ^^^^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:144:27
|
||||
|
|
||||
LL | #[label(no_crate_example, applicability = "machine-applicable")]
|
||||
|
|
@ -112,7 +112,7 @@ error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
|
|||
LL | #[bar("...")]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): only `no_span` is a valid nested attribute
|
||||
error: derive(Diagnostic): no nested attribute expected here
|
||||
--> $DIR/subdiagnostic-derive.rs:215:13
|
||||
|
|
||||
LL | #[label(code = "...")]
|
||||
|
|
@ -175,10 +175,10 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
|
||||
--> $DIR/subdiagnostic-derive.rs:317:44
|
||||
--> $DIR/subdiagnostic-derive.rs:317:27
|
||||
|
|
||||
LL | #[label(no_crate_example, no_crate::example)]
|
||||
| ^
|
||||
| ^^^^^^^^
|
||||
|
||||
error: derive(Diagnostic): attribute specified multiple times
|
||||
--> $DIR/subdiagnostic-derive.rs:330:5
|
||||
|
|
@ -292,7 +292,7 @@ error: derive(Diagnostic): invalid nested attribute
|
|||
LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
|
||||
| ^^^^
|
||||
|
|
||||
= help: only `no_span`, `style` and `applicability` are valid nested attributes
|
||||
= help: only `style` and `applicability` are valid nested attributes
|
||||
|
||||
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
|
||||
--> $DIR/subdiagnostic-derive.rs:530:1
|
||||
|
|
@ -381,10 +381,10 @@ LL | #[applicability]
|
|||
| ^
|
||||
|
||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||
--> $DIR/subdiagnostic-derive.rs:663:34
|
||||
--> $DIR/subdiagnostic-derive.rs:663:28
|
||||
|
|
||||
LL | #[suggestion_part(code("foo"))]
|
||||
| ^
|
||||
| ^^^^^
|
||||
|
||||
error: unexpected token, expected `)`
|
||||
--> $DIR/subdiagnostic-derive.rs:663:28
|
||||
|
|
@ -393,10 +393,10 @@ LL | #[suggestion_part(code("foo"))]
|
|||
| ^^^^^
|
||||
|
||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||
--> $DIR/subdiagnostic-derive.rs:673:41
|
||||
--> $DIR/subdiagnostic-derive.rs:673:28
|
||||
|
|
||||
LL | #[suggestion_part(code("foo", "bar"))]
|
||||
| ^
|
||||
| ^^^^^
|
||||
|
||||
error: unexpected token, expected `)`
|
||||
--> $DIR/subdiagnostic-derive.rs:673:28
|
||||
|
|
@ -405,10 +405,10 @@ LL | #[suggestion_part(code("foo", "bar"))]
|
|||
| ^^^^^
|
||||
|
||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||
--> $DIR/subdiagnostic-derive.rs:683:30
|
||||
--> $DIR/subdiagnostic-derive.rs:683:28
|
||||
|
|
||||
LL | #[suggestion_part(code(3))]
|
||||
| ^
|
||||
| ^
|
||||
|
||||
error: unexpected token, expected `)`
|
||||
--> $DIR/subdiagnostic-derive.rs:683:28
|
||||
|
|
@ -417,10 +417,10 @@ LL | #[suggestion_part(code(3))]
|
|||
| ^
|
||||
|
||||
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
|
||||
--> $DIR/subdiagnostic-derive.rs:693:29
|
||||
--> $DIR/subdiagnostic-derive.rs:693:28
|
||||
|
|
||||
LL | #[suggestion_part(code())]
|
||||
| ^
|
||||
| ^
|
||||
|
||||
error: expected string literal
|
||||
--> $DIR/subdiagnostic-derive.rs:702:30
|
||||
|
|
@ -464,32 +464,26 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")]
|
|||
|
|
||||
= help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
|
||||
|
||||
error: derive(Diagnostic): expected `= "xxx"`
|
||||
--> $DIR/subdiagnostic-derive.rs:777:49
|
||||
error: expected string literal
|
||||
--> $DIR/subdiagnostic-derive.rs:777:51
|
||||
|
|
||||
LL | #[suggestion(no_crate_example, code = "", style = 42)]
|
||||
| ^
|
||||
| ^^
|
||||
|
||||
error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
|
||||
--> $DIR/subdiagnostic-derive.rs:785:48
|
||||
--> $DIR/subdiagnostic-derive.rs:785:43
|
||||
|
|
||||
LL | #[suggestion(no_crate_example, code = "", style)]
|
||||
| ^
|
||||
| ^^^^^
|
||||
|
||||
error: derive(Diagnostic): expected `= "xxx"`
|
||||
--> $DIR/subdiagnostic-derive.rs:793:48
|
||||
|
|
||||
LL | #[suggestion(no_crate_example, code = "", style("foo"))]
|
||||
| ^
|
||||
|
||||
error: expected `,`
|
||||
error: expected `=`
|
||||
--> $DIR/subdiagnostic-derive.rs:793:48
|
||||
|
|
||||
LL | #[suggestion(no_crate_example, code = "", style("foo"))]
|
||||
| ^
|
||||
|
||||
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
|
||||
--> $DIR/subdiagnostic-derive.rs:805:5
|
||||
--> $DIR/subdiagnostic-derive.rs:804:5
|
||||
|
|
||||
LL | #[primary_span]
|
||||
| ^
|
||||
|
|
@ -498,7 +492,7 @@ LL | #[primary_span]
|
|||
= help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
|
||||
|
||||
error: derive(Diagnostic): suggestion without `#[primary_span]` field
|
||||
--> $DIR/subdiagnostic-derive.rs:802:1
|
||||
--> $DIR/subdiagnostic-derive.rs:801:1
|
||||
|
|
||||
LL | #[suggestion(no_crate_example, code = "")]
|
||||
| ^
|
||||
|
|
@ -557,5 +551,5 @@ error: cannot find attribute `bar` in this scope
|
|||
LL | #[bar("...")]
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 84 previous errors
|
||||
error: aborting due to 83 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue