Convert parse_nested_meta to parse_args_with for #[subdiagnostic]
This commit is contained in:
parent
9e61014a8a
commit
5d21a21695
6 changed files with 165 additions and 197 deletions
|
|
@ -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;
|
||||
|
|
@ -437,23 +438,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,
|
||||
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(())
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -428,64 +428,51 @@ 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<'_>,
|
||||
nested: ParseStream<'_>,
|
||||
fields: &impl HasFieldMap,
|
||||
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()))
|
||||
|
|
@ -497,7 +484,7 @@ pub(super) fn build_suggestion_code(
|
|||
} else {
|
||||
// error handled previously
|
||||
quote! { let #code_field = String::new(); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Possible styles for suggestion subdiagnostics.
|
||||
|
|
@ -709,112 +696,95 @@ 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) {
|
||||
// ("no_span", _) => no_span = true,
|
||||
("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 `no_span`, `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 `no_span`, `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, "only `no_span` is a valid nested attribute").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(())
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -803,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)]
|
||||
|
|
|
|||
|
|
@ -277,10 +277,10 @@ LL | #[help(no_crate_help)]
|
|||
| ^
|
||||
|
||||
error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
|
||||
--> $DIR/diagnostic-derive.rs:533: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:541:29
|
||||
|
|
@ -606,14 +606,6 @@ 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:806: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:347:12
|
||||
|
|
||||
|
|
@ -636,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 81 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`.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ 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("...")]
|
||||
|
|
@ -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
|
||||
|
|
@ -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