///
/// This span is *not* considered a ["primary span"][`MultiSpan`]; only
/// the `Span` supplied when creating the diagnostic is primary.
- pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
+ pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self {
self.span.push_span_label(span, label.into());
self
}
/// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
- pub fn span_label(&mut self, span: Span, label: impl Into<String>) -> &mut Self);
+ pub fn span_label(&mut self, span: Span, label: impl Into<DiagnosticMessage>) -> &mut Self);
forward!(
/// Labels all the given spans with the provided label.
) -> Result<proc_macro2::TokenStream, SessionDiagnosticDeriveError> {
let diag = &self.diag;
let field_binding = &info.binding.binding;
+
let name = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
Ok(quote! {})
}
"primary_span" => {
- if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
- return Ok(quote! {
- #diag.set_span(*#field_binding);
- });
- } else {
- throw_span_err!(
- attr.span().unwrap(),
- "the `#[primary_span]` attribute can only be applied to fields of type `Span`"
- );
- }
+ self.report_error_if_not_applied_to_span(attr, info)?;
+ Ok(quote! {
+ #diag.set_span(*#field_binding);
+ })
+ }
+ "label" => {
+ self.report_error_if_not_applied_to_span(attr, info)?;
+ Ok(self.add_subdiagnostic(field_binding, name, "label"))
}
other => throw_span_err!(
attr.span().unwrap(),
&format!("`#[{}]` is not a valid `SessionDiagnostic` field attribute", other)
),
},
- syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
- let formatted_str = self.build_format(&s.value(), attr.span());
- match name {
- "label" => {
- if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
- return Ok(quote! {
- #diag.span_label(*#field_binding, #formatted_str);
- });
- } else {
- throw_span_err!(
- attr.span().unwrap(),
- "the `#[label = ...]` attribute can only be applied to fields of type `Span`"
- );
- }
- }
- other => throw_span_err!(
- attr.span().unwrap(),
- &format!(
- "`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute",
- other
- )
- ),
+ syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => match name {
+ "label" => {
+ self.report_error_if_not_applied_to_span(attr, info)?;
+ Ok(self.add_subdiagnostic(field_binding, name, &s.value()))
}
- }
+ other => throw_span_err!(
+ attr.span().unwrap(),
+ &format!(
+ "`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute",
+ other
+ )
+ ),
+ },
+ syn::Meta::NameValue(_) => throw_span_err!(
+ attr.span().unwrap(),
+ &format!("`#[{} = ...]` is not a valid `SessionDiagnostic` field attribute", name),
+ |diag| diag.help("value must be a string")
+ ),
syn::Meta::List(list) => {
match list.path.segments.iter().last().unwrap().ident.to_string().as_str() {
suggestion_kind @ "suggestion"
),
}
}
- _ => panic!("unhandled meta kind"),
+ }
+ }
+
+ /// Reports an error if the field's type is not `Span`.
+ fn report_error_if_not_applied_to_span(
+ &self,
+ attr: &syn::Attribute,
+ info: FieldInfo<'_>,
+ ) -> Result<(), SessionDiagnosticDeriveError> {
+ if !type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+ let name = attr.path.segments.last().unwrap().ident.to_string();
+ let name = name.as_str();
+ let meta = attr.parse_meta()?;
+
+ throw_span_err!(
+ attr.span().unwrap(),
+ &format!(
+ "the `#[{}{}]` attribute can only be applied to fields of type `Span`",
+ name,
+ match meta {
+ syn::Meta::Path(_) => "",
+ syn::Meta::NameValue(_) => " = ...",
+ syn::Meta::List(_) => "(...)",
+ }
+ )
+ );
+ }
+
+ Ok(())
+ }
+
+ /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and
+ /// `fluent_attr_identifier`.
+ fn add_subdiagnostic(
+ &self,
+ field_binding: &proc_macro2::Ident,
+ kind: &str,
+ fluent_attr_identifier: &str,
+ ) -> proc_macro2::TokenStream {
+ let diag = &self.diag;
+
+ let slug =
+ self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or_else(|| "missing-slug");
+ let fn_name = format_ident!("span_{}", kind);
+ quote! {
+ #diag.#fn_name(
+ *#field_binding,
+ rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier)
+ );
}
}
#[error(code = "E0062", slug = "typeck-field-multiply-specified-in-initializer")]
pub struct FieldMultiplySpecifiedInInitializer {
#[primary_span]
- #[label = "used more than once"]
+ #[label]
pub span: Span,
- #[label = "first use of `{ident}`"]
+ #[label = "previous-use-label"]
pub prev_span: Span,
pub ident: Ident,
}
#[error(code = "E0092", slug = "typeck-unrecognized-atomic-operation")]
pub struct UnrecognizedAtomicOperation<'a> {
#[primary_span]
- #[label = "unrecognized atomic operation"]
+ #[label]
pub span: Span,
pub op: &'a str,
}
#[error(code = "E0094", slug = "typeck-wrong-number-of-generic-arguments-to-intrinsic")]
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[primary_span]
- #[label = "expected {expected} {descr} parameter{expected_pluralize}"]
+ #[label]
pub span: Span,
pub found: usize,
pub expected: usize,
#[error(code = "E0093", slug = "typeck-unrecognized-intrinsic-function")]
pub struct UnrecognizedIntrinsicFunction {
#[primary_span]
- #[label = "unrecognized intrinsic"]
+ #[label]
pub span: Span,
pub name: Symbol,
}
#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[primary_span]
- #[label = "lifetimes do not match {item_kind} in trait"]
+ #[label]
pub span: Span,
- #[label = "lifetimes in impl do not match this {item_kind} in trait"]
+ #[label = "generics-label"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
#[error(code = "E0120", slug = "typeck-drop-impl-on-wrong-item")]
pub struct DropImplOnWrongItem {
#[primary_span]
- #[label = "must be a struct, enum, or union"]
+ #[label]
pub span: Span,
}
pub struct FieldAlreadyDeclared {
pub field_name: Ident,
#[primary_span]
- #[label = "field already declared"]
+ #[label]
pub span: Span,
- #[label = "`{field_name}` first declared here"]
+ #[label = "previous-decl-label"]
pub prev_span: Span,
}
#[error(code = "E0184", slug = "typeck-copy-impl-on-type-with-dtor")]
pub struct CopyImplOnTypeWithDtor {
#[primary_span]
- #[label = "Copy not allowed on types with destructors"]
+ #[label]
pub span: Span,
}
#[error(code = "E0206", slug = "typeck-copy-impl-on-non-adt")]
pub struct CopyImplOnNonAdt {
#[primary_span]
- #[label = "type is not a structure or enumeration"]
+ #[label]
pub span: Span,
}
#[error(code = "E0229", slug = "typeck-assoc-type-binding-not-allowed")]
pub struct AssocTypeBindingNotAllowed {
#[primary_span]
- #[label = "associated type not allowed here"]
+ #[label]
pub span: Span,
}
#[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
pub struct TypeofReservedKeywordUsed {
#[primary_span]
- #[label = "reserved keyword"]
+ #[label]
pub span: Span,
}
pub struct ReturnStmtOutsideOfFnBody {
#[primary_span]
pub span: Span,
- #[label = "the return is part of this body..."]
+ #[label = "encl-body-label"]
pub encl_body_span: Option<Span>,
- #[label = "...not the enclosing function body"]
+ #[label = "encl-fn-label"]
pub encl_fn_span: Option<Span>,
}
#[error(code = "E0719", slug = "typeck-value-of-associated-struct-already-specified")]
pub struct ValueOfAssociatedStructAlreadySpecified {
#[primary_span]
- #[label = "re-bound here"]
+ #[label]
pub span: Span,
- #[label = "`{item_name}` bound here first"]
+ #[label = "previous-bound-label"]
pub prev_span: Span,
pub item_name: Ident,
pub def_path: String,
#[error(code = "E0745", slug = "typeck-address-of-temporary-taken")]
pub struct AddressOfTemporaryTaken {
#[primary_span]
- #[label = "temporary value"]
+ #[label]
pub span: Span,
}
#[error(code = "E0123", slug = "foo")]
struct ErrorWithField {
name: String,
- #[label = "This error has a field, and references {name}"]
+ #[label = "bar"]
span: Span,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct ErrorWithMessageAppliedToField {
- #[label = "this message is applied to a String field"]
+ #[label = "bar"]
//~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
name: String,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct ErrorWithNonexistentField {
- #[label = "This error has a field, and references {name}"]
+ #[suggestion(message = "This is a suggestion", code = "{name}")]
//~^ ERROR `name` doesn't refer to a field on this type
- foo: Span,
+ suggestion: (Span, Applicability),
}
#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
//~^ ERROR invalid format string: expected `'}'`
+#[error(code = "E0123", slug = "foo")]
struct ErrorMissingClosingBrace {
- #[label = "This is missing a closing brace: {name"]
- foo: Span,
+ #[suggestion(message = "This is a suggestion", code = "{name")]
+ suggestion: (Span, Applicability),
name: String,
val: usize,
}
#[derive(SessionDiagnostic)]
-#[error(code = "E0123", slug = "foo")]
//~^ ERROR invalid format string: unmatched `}`
+#[error(code = "E0123", slug = "foo")]
struct ErrorMissingOpeningBrace {
- #[label = "This is missing an opening brace: name}"]
- foo: Span,
+ #[suggestion(message = "This is a suggestion", code = "name}")]
+ suggestion: (Span, Applicability),
name: String,
val: usize,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct LabelOnSpan {
- #[label = "See here"]
+ #[label = "bar"]
sp: Span,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct LabelOnNonSpan {
- #[label = "See here"]
+ #[label = "bar"]
//~^ ERROR the `#[label = ...]` attribute can only be applied to fields of type `Span`
id: u32,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct WrongKindOfAnnotation {
- #[label("wrong kind of annotation for label")]
+ #[label("bar")]
//~^ ERROR invalid annotation list `#[label(...)]`
z: Span,
}
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct OptionsInErrors {
- #[label = "Label message"]
+ #[label = "bar"]
label: Option<Span>,
#[suggestion(message = "suggestion message")]
opt_sugg: Option<(Span, Applicability)>,
name: Ident,
ty: Ty<'tcx>,
#[primary_span]
- #[label = "cannot move out of borrow"]
+ #[label = "bar"]
span: Span,
- #[label = "`{ty}` first borrowed here"]
+ #[label = "qux"]
other_span: Span,
#[suggestion(message = "consider cloning here", code = "{name}.clone()")]
opt_sugg: Option<(Span, Applicability)>,
#[derive(SessionDiagnostic)]
#[error(code = "E0123", slug = "foo")]
struct ErrorWithLifetime<'a> {
- #[label = "Some message that references {name}"]
+ #[label = "bar"]
+ span: Span,
+ name: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(code = "E0123", slug = "foo")]
+struct ErrorWithDefaultLabelAttr<'a> {
+ #[label]
span: Span,
name: &'a str,
}
error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
--> $DIR/session-derive-errors.rs:149:5
|
-LL | #[label = "this message is applied to a String field"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label = "bar"]
+ | ^^^^^^^^^^^^^^^^
error: `name` doesn't refer to a field on this type
- --> $DIR/session-derive-errors.rs:157:5
+ --> $DIR/session-derive-errors.rs:157:52
|
-LL | #[label = "This error has a field, and references {name}"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(message = "This is a suggestion", code = "{name}")]
+ | ^^^^^^^^^^^^^^^
error: invalid format string: expected `'}'` but string was terminated
- --> $DIR/session-derive-errors.rs:163:20
+ --> $DIR/session-derive-errors.rs:162:16
|
LL | #[derive(SessionDiagnostic)]
- | ----------------- in this derive macro expansion
-LL | #[error(code = "E0123", slug = "foo")]
- | - ^ expected `'}'` in format string
- | |
- | because of this opening brace
+ | - ^ expected `'}'` in format string
+ | |
+ | because of this opening brace
|
= note: if you intended to print `{`, you can escape it using `{{`
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: invalid format string: unmatched `}` found
- --> $DIR/session-derive-errors.rs:173:20
+ --> $DIR/session-derive-errors.rs:172:15
|
LL | #[derive(SessionDiagnostic)]
- | ----------------- in this derive macro expansion
-LL | #[error(code = "E0123", slug = "foo")]
- | ^ unmatched `}` in format string
+ | ^ unmatched `}` in format string
|
= note: if you intended to print `}`, you can escape it using `}}`
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: the `#[label = ...]` attribute can only be applied to fields of type `Span`
--> $DIR/session-derive-errors.rs:192:5
|
-LL | #[label = "See here"]
- | ^^^^^^^^^^^^^^^^^^^^^
+LL | #[label = "bar"]
+ | ^^^^^^^^^^^^^^^^
error: `nonsense` is not a valid key for `#[suggestion(...)]`
--> $DIR/session-derive-errors.rs:217:18
error: invalid annotation list `#[label(...)]`
--> $DIR/session-derive-errors.rs:279:7
|
-LL | #[label("wrong kind of annotation for label")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[label("bar")]
+ | ^^^^^^^^^^^^
error: cannot find attribute `nonsense` in this scope
--> $DIR/session-derive-errors.rs:51:3
| ^^^^^^^^
error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
- --> $DIR/session-derive-errors.rs:315:10
+ --> $DIR/session-derive-errors.rs:323:10
|
LL | struct Hello {}
| ------------ method `into_diagnostic_arg` not found for this
--> $DIR/E0184.rs:1:10
|
LL | #[derive(Copy)]
- | ^^^^ Copy not allowed on types with destructors
+ | ^^^^ `Copy` not allowed on types with destructors
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
--> $DIR/exclusive-drop-and-copy.rs:3:10
|
LL | #[derive(Copy, Clone)]
- | ^^^^ Copy not allowed on types with destructors
+ | ^^^^ `Copy` not allowed on types with destructors
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
--> $DIR/exclusive-drop-and-copy.rs:10:10
|
LL | #[derive(Copy, Clone)]
- | ^^^^ Copy not allowed on types with destructors
+ | ^^^^ `Copy` not allowed on types with destructors
|
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)