Skip to content

Commit b7dda57

Browse files
committed
make error codes reflect reality better
1 parent 4310da2 commit b7dda57

38 files changed

+405
-353
lines changed

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean =
121121
literal in `cfg` predicate value must be a boolean
122122
attr_parsing_unsupported_literal_cfg_string =
123123
literal in `cfg` predicate value must be a string
124-
attr_parsing_unsupported_literal_deprecated_kv_pair =
125-
item in `deprecated` must be a key/value pair
126-
attr_parsing_unsupported_literal_deprecated_string =
127-
literal in `deprecated` value must be a string
128124
attr_parsing_unsupported_literal_generic =
129125
unsupported literal
130126
attr_parsing_unsupported_literal_suggestion =

compiler/rustc_attr_parsing/src/attributes/confusables.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
3030
for param in list.mixed() {
3131
let span = param.span();
3232

33-
let Some(lit) = param.lit() else {
34-
cx.expected_string_literal(span);
33+
let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
34+
cx.expected_string_literal(span, param.lit());
3535
continue;
3636
};
3737

38-
this.confusables.push(lit.symbol);
38+
this.confusables.push(lit);
3939
}
4040

4141
this.first_span.get_or_insert(cx.attr_span);

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
77
use crate::context::{AcceptContext, Stage};
88
use crate::parser::ArgParser;
99
use crate::session_diagnostics;
10-
use crate::session_diagnostics::UnsupportedLiteralReason;
1110

1211
pub(crate) struct DeprecationParser;
1312

@@ -26,13 +25,7 @@ fn get<S: Stage>(
2625
if let Some(value_str) = v.value_as_str() {
2726
Some(value_str)
2827
} else {
29-
let lit = v.value_as_lit();
30-
cx.emit_err(session_diagnostics::UnsupportedLiteral {
31-
span: v.value_span,
32-
reason: UnsupportedLiteralReason::DeprecatedString,
33-
is_bytestr: lit.kind.is_bytestr(),
34-
start_point_span: cx.sess().source_map().start_point(lit.span),
35-
});
28+
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
3629
None
3730
}
3831
} else {
@@ -60,57 +53,59 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
6053

6154
let is_rustc = features.staged_api();
6255

63-
if let Some(value) = args.name_value()
64-
&& let Some(value_str) = value.value_as_str()
65-
{
66-
note = Some(value_str)
67-
} else if let Some(list) = args.list() {
68-
for param in list.mixed() {
69-
let param_span = param.span();
70-
let Some(param) = param.meta_item() else {
71-
cx.emit_err(session_diagnostics::UnsupportedLiteral {
72-
span: param_span,
73-
reason: UnsupportedLiteralReason::DeprecatedKvPair,
74-
is_bytestr: false,
75-
start_point_span: cx.sess().source_map().start_point(param_span),
76-
});
77-
return None;
78-
};
56+
match args {
57+
ArgParser::NoArgs => {
58+
// ok
59+
}
60+
ArgParser::List(list) => {
61+
for param in list.mixed() {
62+
let Some(param) = param.meta_item() else {
63+
cx.unexpected_literal(param.span());
64+
return None;
65+
};
7966

80-
let ident_name = param.path_without_args().word_sym();
67+
let ident_name = param.path_without_args().word_sym();
8168

82-
match ident_name {
83-
Some(name @ sym::since) => {
84-
since = Some(get(cx, name, param_span, param.args(), &since)?);
85-
}
86-
Some(name @ sym::note) => {
87-
note = Some(get(cx, name, param_span, param.args(), &note)?);
88-
}
89-
Some(name @ sym::suggestion) => {
90-
if !features.deprecated_suggestion() {
91-
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
92-
span: param_span,
93-
is_nightly: cx.sess().is_nightly_build(),
94-
details: (),
95-
});
69+
match ident_name {
70+
Some(name @ sym::since) => {
71+
since = Some(get(cx, name, param.span(), param.args(), &since)?);
72+
}
73+
Some(name @ sym::note) => {
74+
note = Some(get(cx, name, param.span(), param.args(), &note)?);
9675
}
76+
Some(name @ sym::suggestion) => {
77+
if !features.deprecated_suggestion() {
78+
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
79+
span: param.span(),
80+
is_nightly: cx.sess().is_nightly_build(),
81+
details: (),
82+
});
83+
}
9784

98-
suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
99-
}
100-
_ => {
101-
cx.unknown_key(
102-
param_span,
103-
param.path_without_args().to_string(),
104-
if features.deprecated_suggestion() {
105-
&["since", "note", "suggestion"]
106-
} else {
107-
&["since", "note"]
108-
},
109-
);
110-
return None;
85+
suggestion = Some(get(cx, name, param.span(), param.args(), &suggestion)?);
86+
}
87+
_ => {
88+
cx.unknown_key(
89+
param.span(),
90+
param.path_without_args().to_string(),
91+
if features.deprecated_suggestion() {
92+
&["since", "note", "suggestion"]
93+
} else {
94+
&["since", "note"]
95+
},
96+
);
97+
return None;
98+
}
11199
}
112100
}
113101
}
102+
ArgParser::NameValue(v) => {
103+
let Some(value) = v.value_as_str() else {
104+
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
105+
return None;
106+
};
107+
note = Some(value);
108+
}
114109
}
115110

116111
let since = if let Some(since) = since {

compiler/rustc_attr_parsing/src/attributes/inline.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
7373
};
7474

7575
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
76-
cx.expected_string_literal(l.span());
76+
cx.expected_string_literal(l.span(), l.lit());
7777
return None;
7878
};
7979

8080
Some(reason)
8181
}
8282
ArgParser::NameValue(v) => {
8383
let Some(reason) = v.value_as_str() else {
84-
cx.expected_string_literal(v.value_span);
84+
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
8585
return None;
8686
};
8787

compiler/rustc_attr_parsing/src/attributes/repr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
3434
let mut reprs = Vec::new();
3535

3636
let Some(list) = args.list() else {
37+
cx.expected_list(cx.attr_span);
3738
return reprs;
3839
};
3940

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut};
44
use std::sync::LazyLock;
55

66
use private::Sealed;
7-
use rustc_ast as ast;
7+
use rustc_ast::{self as ast, MetaItemLit};
88
use rustc_ast::NodeId;
99
use rustc_attr_data_structures::AttributeKind;
1010
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
@@ -217,13 +217,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
217217
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
218218
}
219219

220-
pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed {
220+
/// error that a string literal was expected.
221+
/// You can optionally give the literal you did find (which you found not to be a string literal)
222+
/// which can make better errors. For example, if the literal was a byte string it will suggest
223+
/// removing the `b` prefix.
224+
pub(crate) fn expected_string_literal(
225+
&self,
226+
span: Span,
227+
actual_literal: Option<&MetaItemLit>,
228+
) -> ErrorGuaranteed {
221229
self.emit_err(AttributeParseError {
222230
span,
223231
attr_span: self.attr_span,
224232
template: self.template.clone(),
225233
attribute: self.attr_path.clone(),
226-
reason: AttributeParseErrorReason::ExpectedStringLiteral,
234+
reason: AttributeParseErrorReason::ExpectedStringLiteral {
235+
byte_string: actual_literal.and_then(|i| {
236+
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
237+
}),
238+
},
227239
})
228240
}
229241

@@ -260,6 +272,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
260272
})
261273
}
262274

275+
/// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
276+
/// was expected *not* to be a literal, but instead a meta item.
277+
pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
278+
self.emit_err(AttributeParseError {
279+
span,
280+
attr_span: self.attr_span,
281+
template: self.template.clone(),
282+
attribute: self.attr_path.clone(),
283+
reason: AttributeParseErrorReason::UnexpectedLiteral,
284+
})
285+
}
286+
263287
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
264288
self.emit_err(AttributeParseError {
265289
span,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason {
1616
Generic,
1717
CfgString,
1818
CfgBoolean,
19-
DeprecatedString,
20-
DeprecatedKvPair,
2119
}
2220

2321
#[derive(Diagnostic)]
@@ -190,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue {
190188
}
191189

192190
/// Error code: E0565
191+
// FIXME(jdonszelmann): slowly phased out
193192
pub(crate) struct UnsupportedLiteral {
194193
pub span: Span,
195194
pub reason: UnsupportedLiteralReason,
@@ -212,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
212211
UnsupportedLiteralReason::CfgBoolean => {
213212
fluent::attr_parsing_unsupported_literal_cfg_boolean
214213
}
215-
UnsupportedLiteralReason::DeprecatedString => {
216-
fluent::attr_parsing_unsupported_literal_deprecated_string
217-
}
218-
UnsupportedLiteralReason::DeprecatedKvPair => {
219-
fluent::attr_parsing_unsupported_literal_deprecated_kv_pair
220-
}
221214
},
222215
);
223216
diag.span(self.span);
@@ -473,9 +466,10 @@ pub(crate) struct UnrecognizedReprHint {
473466
}
474467

475468
pub(crate) enum AttributeParseErrorReason {
476-
ExpectedStringLiteral,
469+
ExpectedStringLiteral { byte_string: Option<Span> },
477470
ExpectedSingleArgument,
478471
ExpectedList,
472+
UnexpectedLiteral,
479473
ExpectedNameValue(Option<Symbol>),
480474
DuplicateKey(Symbol),
481475
ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
@@ -497,27 +491,44 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
497491
diag.span(self.attr_span);
498492
diag.code(E0539);
499493
match self.reason {
500-
AttributeParseErrorReason::ExpectedStringLiteral => {
501-
diag.span_note(self.span, "expected a string literal here");
494+
AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
495+
if let Some(start_point_span) = byte_string {
496+
diag.span_suggestion(
497+
start_point_span,
498+
fluent::attr_parsing_unsupported_literal_suggestion,
499+
"",
500+
Applicability::MaybeIncorrect,
501+
);
502+
diag.note("expected a normal string literal, not a byte string literal");
503+
504+
return diag;
505+
} else {
506+
diag.span_label(self.span, "expected a string literal here");
507+
}
502508
}
503509
AttributeParseErrorReason::ExpectedSingleArgument => {
504-
diag.span_note(self.span, "expected a single argument here");
510+
diag.span_label(self.span, "expected a single argument here");
511+
diag.code(E0540);
505512
}
506513
AttributeParseErrorReason::ExpectedList => {
507-
diag.span_note(self.span, "expected this to be a list");
514+
diag.span_label(self.span, "expected this to be a list");
508515
}
509516
AttributeParseErrorReason::DuplicateKey(key) => {
510-
diag.span_note(self.span, format!("found `{key}` used as a key more than once"));
517+
diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
511518
diag.code(E0538);
512519
}
520+
AttributeParseErrorReason::UnexpectedLiteral => {
521+
diag.span_label(self.span, format!("didn't expect a literal here"));
522+
diag.code(E0565);
523+
}
513524
AttributeParseErrorReason::ExpectedNameValue(None) => {
514-
diag.span_note(
525+
diag.span_label(
515526
self.span,
516527
format!("expected this to be of the form `{name} = \"...\"`"),
517528
);
518529
}
519530
AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
520-
diag.span_note(
531+
diag.span_label(
521532
self.span,
522533
format!("expected this to be of the form `{name} = \"...\"`"),
523534
);
@@ -527,13 +538,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
527538
match possibilities.as_slice() {
528539
&[] => {}
529540
&[x] => {
530-
diag.span_note(
541+
diag.span_label(
531542
self.span,
532543
format!("the only valid argument here is {quote}{x}{quote}"),
533544
);
534545
}
535546
[first, second] => {
536-
diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
547+
diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
537548
}
538549
[first @ .., second_to_last, last] => {
539550
let mut res = String::new();
@@ -544,7 +555,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
544555
"{quote}{second_to_last}{quote} or {quote}{last}{quote}"
545556
));
546557

547-
diag.span_note(self.span, format!("valid arguments are {res}"));
558+
diag.span_label(self.span, format!("valid arguments are {res}"));
548559
}
549560
}
550561
}

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -208,28 +208,13 @@ pub(crate) struct OutOfRangeInteger {
208208
pub span: Span,
209209
}
210210

211-
#[derive(Diagnostic)]
212-
#[diag(codegen_ssa_expected_one_argument, code = E0534)]
213-
pub(crate) struct ExpectedOneArgument {
214-
#[primary_span]
215-
pub span: Span,
216-
}
217-
218211
#[derive(Diagnostic)]
219212
#[diag(codegen_ssa_expected_one_argument, code = E0722)]
220213
pub(crate) struct ExpectedOneArgumentOptimize {
221214
#[primary_span]
222215
pub span: Span,
223216
}
224217

225-
#[derive(Diagnostic)]
226-
#[diag(codegen_ssa_invalid_argument, code = E0535)]
227-
#[help]
228-
pub(crate) struct InvalidArgument {
229-
#[primary_span]
230-
pub span: Span,
231-
}
232-
233218
#[derive(Diagnostic)]
234219
#[diag(codegen_ssa_invalid_argument, code = E0722)]
235220
pub(crate) struct InvalidArgumentOptimize {

compiler/rustc_error_codes/src/error_codes/E0534.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
#### Note: this error code is no longer emitted by the compiler
2+
3+
This is because it was too specific to the `inline` attribute.
4+
Similar diagnostics occur for other attributes too.
5+
The example here will now emit `E0540`
6+
17
The `inline` attribute was malformed.
28

39
Erroneous code example:
410

5-
```compile_fail,E0534
11+
```compile_fail,E0540
612
#[inline()] // error: expected one argument
713
pub fn something() {}
814

0 commit comments

Comments
 (0)