Skip to content

Commit 0005f62

Browse files
committed
Refactor diagnostics in handle_errors function
1 parent e0dc8d7 commit 0005f62

File tree

5 files changed

+254
-31
lines changed

5 files changed

+254
-31
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use rustc_span::hygiene::Transparency;
1414
use rustc_span::{symbol::sym, symbol::Symbol, Span};
1515
use std::num::NonZeroU32;
1616

17+
use crate::session_diagnostics;
18+
1719
pub fn is_builtin_attr(attr: &Attribute) -> bool {
1820
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
1921
}
@@ -25,46 +27,38 @@ enum AttrError {
2527
NonIdentFeature,
2628
MissingFeature,
2729
MultipleStabilityLevels,
28-
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
30+
UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
31+
}
32+
33+
pub(crate) enum UnsupportedLiteralReason {
34+
Generic,
35+
CfgString,
36+
DeprecatedString,
37+
DeprecatedKvPair,
2938
}
3039

3140
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
32-
let diag = &sess.span_diagnostic;
3341
match error {
3442
AttrError::MultipleItem(item) => {
35-
struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
43+
sess.emit_err(session_diagnostics::MultipleItem { span, item });
3644
}
3745
AttrError::UnknownMetaItem(item, expected) => {
38-
let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
39-
struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
40-
.span_label(span, format!("expected one of {}", expected.join(", ")))
41-
.emit();
46+
sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
4247
}
4348
AttrError::MissingSince => {
44-
struct_span_err!(diag, span, E0542, "missing 'since'").emit();
49+
sess.emit_err(session_diagnostics::MissingSince { span });
4550
}
4651
AttrError::NonIdentFeature => {
47-
struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
52+
sess.emit_err(session_diagnostics::NonIdentFeature { span });
4853
}
4954
AttrError::MissingFeature => {
50-
struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
55+
sess.emit_err(session_diagnostics::MissingFeature { span });
5156
}
5257
AttrError::MultipleStabilityLevels => {
53-
struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
58+
sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
5459
}
55-
AttrError::UnsupportedLiteral(msg, is_bytestr) => {
56-
let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
57-
if is_bytestr {
58-
if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
59-
err.span_suggestion(
60-
span,
61-
"consider removing the prefix",
62-
&lint_str[1..],
63-
Applicability::MaybeIncorrect,
64-
);
65-
}
66-
}
67-
err.emit();
60+
AttrError::UnsupportedLiteral(reason, is_bytestr) => {
61+
sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr });
6862
}
6963
}
7064
}
@@ -326,7 +320,7 @@ where
326320
handle_errors(
327321
&sess.parse_sess,
328322
meta.span(),
329-
AttrError::UnsupportedLiteral("unsupported literal", false),
323+
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
330324
);
331325
continue 'outer;
332326
};
@@ -494,7 +488,10 @@ where
494488
handle_errors(
495489
&sess.parse_sess,
496490
lit.span,
497-
AttrError::UnsupportedLiteral("unsupported literal", false),
491+
AttrError::UnsupportedLiteral(
492+
UnsupportedLiteralReason::Generic,
493+
false,
494+
),
498495
);
499496
continue 'outer;
500497
}
@@ -711,7 +708,7 @@ pub fn eval_condition(
711708
handle_errors(
712709
sess,
713710
mi.span(),
714-
AttrError::UnsupportedLiteral("unsupported literal", false),
711+
AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
715712
);
716713
return false;
717714
}
@@ -790,7 +787,7 @@ pub fn eval_condition(
790787
sess,
791788
lit.span,
792789
AttrError::UnsupportedLiteral(
793-
"literal in `cfg` predicate value must be a string",
790+
UnsupportedLiteralReason::CfgString,
794791
lit.kind.is_bytestr(),
795792
),
796793
);
@@ -870,8 +867,7 @@ where
870867
&sess.parse_sess,
871868
lit.span,
872869
AttrError::UnsupportedLiteral(
873-
"literal in `deprecated` \
874-
value must be a string",
870+
UnsupportedLiteralReason::DeprecatedString,
875871
lit.kind.is_bytestr(),
876872
),
877873
);
@@ -934,7 +930,7 @@ where
934930
&sess.parse_sess,
935931
lit.span,
936932
AttrError::UnsupportedLiteral(
937-
"item in `deprecated` must be a key/value pair",
933+
UnsupportedLiteralReason::DeprecatedKvPair,
938934
false,
939935
),
940936
);

compiler/rustc_attr/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
extern crate rustc_macros;
1111

1212
mod builtin;
13+
mod session_diagnostics;
1314

1415
pub use builtin::*;
1516
pub use IntType::*;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
use std::num::IntErrorKind;
2+
3+
use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed};
4+
use rustc_macros::SessionDiagnostic;
5+
use rustc_session::{parse::ParseSess, SessionDiagnostic};
6+
use rustc_span::Span;
7+
8+
use crate::UnsupportedLiteralReason;
9+
10+
#[derive(SessionDiagnostic)]
11+
#[error(attr::multiple_item, code = "E0538")]
12+
pub(crate) struct MultipleItem {
13+
#[primary_span]
14+
pub span: Span,
15+
16+
pub item: String,
17+
}
18+
19+
#[derive(SessionDiagnostic)]
20+
#[error(attr::missing_since, code = "E0542")]
21+
pub(crate) struct MissingSince {
22+
#[primary_span]
23+
pub span: Span,
24+
}
25+
26+
#[derive(SessionDiagnostic)]
27+
#[error(attr::non_ident_feature, code = "E0546")]
28+
pub(crate) struct NonIdentFeature {
29+
#[primary_span]
30+
pub span: Span,
31+
}
32+
33+
#[derive(SessionDiagnostic)]
34+
#[error(attr::missing_feature, code = "E0546")]
35+
pub(crate) struct MissingFeature {
36+
#[primary_span]
37+
pub span: Span,
38+
}
39+
40+
#[derive(SessionDiagnostic)]
41+
#[error(attr::multiple_stability_levels, code = "E0544")]
42+
pub(crate) struct MultipleStabilityLevels {
43+
#[primary_span]
44+
pub span: Span,
45+
}
46+
47+
#[derive(SessionDiagnostic)]
48+
#[error(attr::invalid_meta_item, code = "E0539")]
49+
pub(crate) struct InvalidMetaItem {
50+
#[primary_span]
51+
pub span: Span,
52+
}
53+
54+
#[derive(SessionDiagnostic)]
55+
#[error(attr::missing_issue, code = "E0547")]
56+
pub(crate) struct MissingIssue {
57+
#[primary_span]
58+
pub span: Span,
59+
}
60+
61+
#[derive(SessionDiagnostic)]
62+
#[error(attr::rustc_promotable_pairing, code = "E0717")]
63+
pub(crate) struct RustcPromotablePairing {
64+
#[primary_span]
65+
pub span: Span,
66+
}
67+
68+
#[derive(SessionDiagnostic)]
69+
#[error(attr::rustc_allowed_unstable_pairing, code = "E0789")]
70+
pub(crate) struct RustcAllowedUnstablePairing {
71+
#[primary_span]
72+
pub span: Span,
73+
}
74+
75+
#[derive(SessionDiagnostic)]
76+
#[error(attr::soft_no_args)]
77+
pub(crate) struct SoftNoArgs {
78+
#[primary_span]
79+
pub span: Span,
80+
}
81+
82+
#[derive(SessionDiagnostic)]
83+
#[error(attr::invalid_issue_string, code = "E0545")]
84+
pub(crate) struct InvalidIssueString {
85+
#[primary_span]
86+
pub span: Span,
87+
88+
#[subdiagnostic]
89+
pub cause: Option<InvalidIssueStringCause>,
90+
}
91+
92+
// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
93+
// translatable.
94+
#[derive(SessionSubdiagnostic)]
95+
pub(crate) enum InvalidIssueStringCause {
96+
#[label(attr::must_not_be_zero)]
97+
MustNotBeZero {
98+
#[primary_span]
99+
span: Span,
100+
},
101+
102+
#[label(attr::empty)]
103+
Empty {
104+
#[primary_span]
105+
span: Span,
106+
},
107+
108+
#[label(attr::invalid_digit)]
109+
InvalidDigit {
110+
#[primary_span]
111+
span: Span,
112+
},
113+
114+
#[label(attr::pos_overflow)]
115+
PosOverflow {
116+
#[primary_span]
117+
span: Span,
118+
},
119+
120+
#[label(attr::neg_overflow)]
121+
NegOverflow {
122+
#[primary_span]
123+
span: Span,
124+
},
125+
}
126+
127+
impl InvalidIssueStringCause {
128+
pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
129+
match kind {
130+
IntErrorKind::Empty => Some(Self::Empty { span }),
131+
IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
132+
IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
133+
IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
134+
IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
135+
_ => None,
136+
}
137+
}
138+
}
139+
140+
pub(crate) struct UnknownMetaItem<'a> {
141+
pub span: Span,
142+
pub item: String,
143+
pub expected: &'a [&'a str],
144+
}
145+
146+
// Manual implementation to be able to format `expected` items correctly.
147+
impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
148+
fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
149+
let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
150+
let mut diag = sess.span_diagnostic.struct_span_err_with_code(
151+
self.span,
152+
fluent::attr::unknown_meta_item,
153+
error_code!(E0541),
154+
);
155+
diag.set_arg("item", self.item);
156+
diag.set_arg("expected", expected.join(", "));
157+
diag.span_label(self.span, fluent::attr::label);
158+
diag
159+
}
160+
}
161+
162+
pub(crate) struct UnsupportedLiteral {
163+
pub span: Span,
164+
pub reason: UnsupportedLiteralReason,
165+
pub is_bytestr: bool,
166+
}
167+
168+
impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
169+
fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
170+
let mut diag = sess.span_diagnostic.struct_span_err_with_code(
171+
self.span,
172+
match self.reason {
173+
UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
174+
UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
175+
UnsupportedLiteralReason::DeprecatedString => {
176+
fluent::attr::unsupported_literal_deprecated_string
177+
}
178+
UnsupportedLiteralReason::DeprecatedKvPair => {
179+
fluent::attr::unsupported_literal_deprecated_kv_pair
180+
}
181+
},
182+
error_code!(E0565),
183+
);
184+
if self.is_bytestr {
185+
if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) {
186+
diag.span_suggestion(
187+
self.span,
188+
fluent::attr::unsupported_literal_suggestion,
189+
&lint_str[1..],
190+
Applicability::MaybeIncorrect,
191+
);
192+
}
193+
}
194+
diag
195+
}
196+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
attr_multiple_item =
2+
multiple '{$item}' items
3+
4+
attr_unknown_meta_item =
5+
unknown meta item '{$item}'
6+
.label = expected one of {$expected}
7+
8+
attr_missing_since =
9+
missing 'since'
10+
11+
attr_non_ident_feature =
12+
'feature' is not an identifier
13+
14+
attr_missing_feature =
15+
missing 'feature'
16+
17+
attr_multiple_stability_levels =
18+
multiple stability levels
19+
20+
attr_unsupported_literal_generic =
21+
unsupported literal
22+
attr_unsupported_literal_cfg_string =
23+
literal in `cfg` predicate value must be a string
24+
attr_unsupported_literal_deprecated_string =
25+
literal in `deprecated` value must be a string
26+
attr_unsupported_literal_deprecated_kv_pair =
27+
item in `deprecated` must be a key/value pair
28+
attr_unsupported_literal_suggestion =
29+
consider removing the prefix

compiler/rustc_error_messages/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
3333
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
3434
fluent_messages! {
3535
ast_passes => "../locales/en-US/ast_passes.ftl",
36+
attr => "../locales/en-US/attr.ftl",
3637
borrowck => "../locales/en-US/borrowck.ftl",
3738
builtin_macros => "../locales/en-US/builtin_macros.ftl",
3839
const_eval => "../locales/en-US/const_eval.ftl",

0 commit comments

Comments
 (0)