Refactor diagnostics in handle_errors
function
This commit is contained in:
parent
e0dc8d7801
commit
0005f628f0
5 changed files with 254 additions and 31 deletions
|
@ -14,6 +14,8 @@ use rustc_span::hygiene::Transparency;
|
||||||
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
use crate::session_diagnostics;
|
||||||
|
|
||||||
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
||||||
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
|
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
|
||||||
}
|
}
|
||||||
|
@ -25,46 +27,38 @@ enum AttrError {
|
||||||
NonIdentFeature,
|
NonIdentFeature,
|
||||||
MissingFeature,
|
MissingFeature,
|
||||||
MultipleStabilityLevels,
|
MultipleStabilityLevels,
|
||||||
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
|
UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum UnsupportedLiteralReason {
|
||||||
|
Generic,
|
||||||
|
CfgString,
|
||||||
|
DeprecatedString,
|
||||||
|
DeprecatedKvPair,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
||||||
let diag = &sess.span_diagnostic;
|
|
||||||
match error {
|
match error {
|
||||||
AttrError::MultipleItem(item) => {
|
AttrError::MultipleItem(item) => {
|
||||||
struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
|
sess.emit_err(session_diagnostics::MultipleItem { span, item });
|
||||||
}
|
}
|
||||||
AttrError::UnknownMetaItem(item, expected) => {
|
AttrError::UnknownMetaItem(item, expected) => {
|
||||||
let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
|
sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
|
||||||
struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
|
|
||||||
.span_label(span, format!("expected one of {}", expected.join(", ")))
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
AttrError::MissingSince => {
|
AttrError::MissingSince => {
|
||||||
struct_span_err!(diag, span, E0542, "missing 'since'").emit();
|
sess.emit_err(session_diagnostics::MissingSince { span });
|
||||||
}
|
}
|
||||||
AttrError::NonIdentFeature => {
|
AttrError::NonIdentFeature => {
|
||||||
struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
|
sess.emit_err(session_diagnostics::NonIdentFeature { span });
|
||||||
}
|
}
|
||||||
AttrError::MissingFeature => {
|
AttrError::MissingFeature => {
|
||||||
struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
|
sess.emit_err(session_diagnostics::MissingFeature { span });
|
||||||
}
|
}
|
||||||
AttrError::MultipleStabilityLevels => {
|
AttrError::MultipleStabilityLevels => {
|
||||||
struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
|
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
|
||||||
}
|
}
|
||||||
AttrError::UnsupportedLiteral(msg, is_bytestr) => {
|
AttrError::UnsupportedLiteral(reason, is_bytestr) => {
|
||||||
let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
|
sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr });
|
||||||
if is_bytestr {
|
|
||||||
if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
|
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
"consider removing the prefix",
|
|
||||||
&lint_str[1..],
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,7 +320,7 @@ where
|
||||||
handle_errors(
|
handle_errors(
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
meta.span(),
|
meta.span(),
|
||||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||||
);
|
);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
};
|
};
|
||||||
|
@ -494,7 +488,10 @@ where
|
||||||
handle_errors(
|
handle_errors(
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
lit.span,
|
lit.span,
|
||||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
AttrError::UnsupportedLiteral(
|
||||||
|
UnsupportedLiteralReason::Generic,
|
||||||
|
false,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
|
@ -711,7 +708,7 @@ pub fn eval_condition(
|
||||||
handle_errors(
|
handle_errors(
|
||||||
sess,
|
sess,
|
||||||
mi.span(),
|
mi.span(),
|
||||||
AttrError::UnsupportedLiteral("unsupported literal", false),
|
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -790,7 +787,7 @@ pub fn eval_condition(
|
||||||
sess,
|
sess,
|
||||||
lit.span,
|
lit.span,
|
||||||
AttrError::UnsupportedLiteral(
|
AttrError::UnsupportedLiteral(
|
||||||
"literal in `cfg` predicate value must be a string",
|
UnsupportedLiteralReason::CfgString,
|
||||||
lit.kind.is_bytestr(),
|
lit.kind.is_bytestr(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -870,8 +867,7 @@ where
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
lit.span,
|
lit.span,
|
||||||
AttrError::UnsupportedLiteral(
|
AttrError::UnsupportedLiteral(
|
||||||
"literal in `deprecated` \
|
UnsupportedLiteralReason::DeprecatedString,
|
||||||
value must be a string",
|
|
||||||
lit.kind.is_bytestr(),
|
lit.kind.is_bytestr(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -934,7 +930,7 @@ where
|
||||||
&sess.parse_sess,
|
&sess.parse_sess,
|
||||||
lit.span,
|
lit.span,
|
||||||
AttrError::UnsupportedLiteral(
|
AttrError::UnsupportedLiteral(
|
||||||
"item in `deprecated` must be a key/value pair",
|
UnsupportedLiteralReason::DeprecatedKvPair,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
extern crate rustc_macros;
|
extern crate rustc_macros;
|
||||||
|
|
||||||
mod builtin;
|
mod builtin;
|
||||||
|
mod session_diagnostics;
|
||||||
|
|
||||||
pub use builtin::*;
|
pub use builtin::*;
|
||||||
pub use IntType::*;
|
pub use IntType::*;
|
||||||
|
|
196
compiler/rustc_attr/src/session_diagnostics.rs
Normal file
196
compiler/rustc_attr/src/session_diagnostics.rs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
use std::num::IntErrorKind;
|
||||||
|
|
||||||
|
use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
|
use rustc_macros::SessionDiagnostic;
|
||||||
|
use rustc_session::{parse::ParseSess, SessionDiagnostic};
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use crate::UnsupportedLiteralReason;
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::multiple_item, code = "E0538")]
|
||||||
|
pub(crate) struct MultipleItem {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
|
||||||
|
pub item: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::missing_since, code = "E0542")]
|
||||||
|
pub(crate) struct MissingSince {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::non_ident_feature, code = "E0546")]
|
||||||
|
pub(crate) struct NonIdentFeature {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::missing_feature, code = "E0546")]
|
||||||
|
pub(crate) struct MissingFeature {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::multiple_stability_levels, code = "E0544")]
|
||||||
|
pub(crate) struct MultipleStabilityLevels {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::invalid_meta_item, code = "E0539")]
|
||||||
|
pub(crate) struct InvalidMetaItem {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::missing_issue, code = "E0547")]
|
||||||
|
pub(crate) struct MissingIssue {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::rustc_promotable_pairing, code = "E0717")]
|
||||||
|
pub(crate) struct RustcPromotablePairing {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::rustc_allowed_unstable_pairing, code = "E0789")]
|
||||||
|
pub(crate) struct RustcAllowedUnstablePairing {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::soft_no_args)]
|
||||||
|
pub(crate) struct SoftNoArgs {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(attr::invalid_issue_string, code = "E0545")]
|
||||||
|
pub(crate) struct InvalidIssueString {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub cause: Option<InvalidIssueStringCause>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
|
||||||
|
// translatable.
|
||||||
|
#[derive(SessionSubdiagnostic)]
|
||||||
|
pub(crate) enum InvalidIssueStringCause {
|
||||||
|
#[label(attr::must_not_be_zero)]
|
||||||
|
MustNotBeZero {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[label(attr::empty)]
|
||||||
|
Empty {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[label(attr::invalid_digit)]
|
||||||
|
InvalidDigit {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[label(attr::pos_overflow)]
|
||||||
|
PosOverflow {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[label(attr::neg_overflow)]
|
||||||
|
NegOverflow {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvalidIssueStringCause {
|
||||||
|
pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
|
||||||
|
match kind {
|
||||||
|
IntErrorKind::Empty => Some(Self::Empty { span }),
|
||||||
|
IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
|
||||||
|
IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
|
||||||
|
IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
|
||||||
|
IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct UnknownMetaItem<'a> {
|
||||||
|
pub span: Span,
|
||||||
|
pub item: String,
|
||||||
|
pub expected: &'a [&'a str],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual implementation to be able to format `expected` items correctly.
|
||||||
|
impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
|
||||||
|
fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||||
|
let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
|
||||||
|
let mut diag = sess.span_diagnostic.struct_span_err_with_code(
|
||||||
|
self.span,
|
||||||
|
fluent::attr::unknown_meta_item,
|
||||||
|
error_code!(E0541),
|
||||||
|
);
|
||||||
|
diag.set_arg("item", self.item);
|
||||||
|
diag.set_arg("expected", expected.join(", "));
|
||||||
|
diag.span_label(self.span, fluent::attr::label);
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct UnsupportedLiteral {
|
||||||
|
pub span: Span,
|
||||||
|
pub reason: UnsupportedLiteralReason,
|
||||||
|
pub is_bytestr: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
|
||||||
|
fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||||
|
let mut diag = sess.span_diagnostic.struct_span_err_with_code(
|
||||||
|
self.span,
|
||||||
|
match self.reason {
|
||||||
|
UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
|
||||||
|
UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
|
||||||
|
UnsupportedLiteralReason::DeprecatedString => {
|
||||||
|
fluent::attr::unsupported_literal_deprecated_string
|
||||||
|
}
|
||||||
|
UnsupportedLiteralReason::DeprecatedKvPair => {
|
||||||
|
fluent::attr::unsupported_literal_deprecated_kv_pair
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error_code!(E0565),
|
||||||
|
);
|
||||||
|
if self.is_bytestr {
|
||||||
|
if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) {
|
||||||
|
diag.span_suggestion(
|
||||||
|
self.span,
|
||||||
|
fluent::attr::unsupported_literal_suggestion,
|
||||||
|
&lint_str[1..],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
}
|
29
compiler/rustc_error_messages/locales/en-US/attr.ftl
Normal file
29
compiler/rustc_error_messages/locales/en-US/attr.ftl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
attr_multiple_item =
|
||||||
|
multiple '{$item}' items
|
||||||
|
|
||||||
|
attr_unknown_meta_item =
|
||||||
|
unknown meta item '{$item}'
|
||||||
|
.label = expected one of {$expected}
|
||||||
|
|
||||||
|
attr_missing_since =
|
||||||
|
missing 'since'
|
||||||
|
|
||||||
|
attr_non_ident_feature =
|
||||||
|
'feature' is not an identifier
|
||||||
|
|
||||||
|
attr_missing_feature =
|
||||||
|
missing 'feature'
|
||||||
|
|
||||||
|
attr_multiple_stability_levels =
|
||||||
|
multiple stability levels
|
||||||
|
|
||||||
|
attr_unsupported_literal_generic =
|
||||||
|
unsupported literal
|
||||||
|
attr_unsupported_literal_cfg_string =
|
||||||
|
literal in `cfg` predicate value must be a string
|
||||||
|
attr_unsupported_literal_deprecated_string =
|
||||||
|
literal in `deprecated` value must be a string
|
||||||
|
attr_unsupported_literal_deprecated_kv_pair =
|
||||||
|
item in `deprecated` must be a key/value pair
|
||||||
|
attr_unsupported_literal_suggestion =
|
||||||
|
consider removing the prefix
|
|
@ -33,6 +33,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
|
||||||
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
|
||||||
fluent_messages! {
|
fluent_messages! {
|
||||||
ast_passes => "../locales/en-US/ast_passes.ftl",
|
ast_passes => "../locales/en-US/ast_passes.ftl",
|
||||||
|
attr => "../locales/en-US/attr.ftl",
|
||||||
borrowck => "../locales/en-US/borrowck.ftl",
|
borrowck => "../locales/en-US/borrowck.ftl",
|
||||||
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
||||||
const_eval => "../locales/en-US/const_eval.ftl",
|
const_eval => "../locales/en-US/const_eval.ftl",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue