Skip to content

Commit 38c9f10

Browse files
committed
use consistent attr errors in all attribute parsers
1 parent d774bc3 commit 38c9f10

23 files changed

+308
-154
lines changed

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
2727
[1] attribute must be of the form {$suggestions}
2828
*[other] valid forms for the attribute are {$suggestions}
2929
}
30-
attr_parsing_incorrect_meta_item = expected a quoted string literal
31-
attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
3230
3331
attr_parsing_incorrect_repr_format_align_one_arg =
3432
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
@@ -85,9 +83,6 @@ attr_parsing_missing_note =
8583
attr_parsing_missing_since =
8684
missing 'since'
8785
88-
attr_parsing_multiple_item =
89-
multiple '{$item}' items
90-
9186
attr_parsing_multiple_stability_levels =
9287
multiple stability levels
9388

compiler/rustc_attr_parsing/src/attributes/confusables.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
1919
template!(List: r#""name1", "name2", ..."#),
2020
|this, cx, args| {
2121
let Some(list) = args.list() else {
22-
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
23-
// NOTE: currently subsequent attributes are silently ignored using
24-
// tcx.get_attr().
22+
cx.expected_list(cx.attr_span);
2523
return;
2624
};
2725

@@ -33,13 +31,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
3331
let span = param.span();
3432

3533
let Some(lit) = param.lit() else {
36-
cx.emit_err(session_diagnostics::IncorrectMetaItem {
37-
span,
38-
suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
39-
lo: span.shrink_to_lo(),
40-
hi: span.shrink_to_hi(),
41-
}),
42-
});
34+
cx.expected_string_literal(span);
4335
continue;
4436
};
4537

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn get<S: Stage>(
1919
item: &Option<Symbol>,
2020
) -> Option<Symbol> {
2121
if item.is_some() {
22-
cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() });
22+
cx.duplicate_key(param_span, name);
2323
return None;
2424
}
2525
if let Some(v) = arg.name_value() {
@@ -36,8 +36,7 @@ fn get<S: Stage>(
3636
None
3737
}
3838
} else {
39-
// FIXME(jdonszelmann): suggestion?
40-
cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
39+
cx.expected_name_value(param_span, Some(name));
4140
None
4241
}
4342
}
@@ -99,15 +98,15 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
9998
suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
10099
}
101100
_ => {
102-
cx.emit_err(session_diagnostics::UnknownMetaItem {
103-
span: param_span,
104-
item: param.path().to_string(),
105-
expected: if features.deprecated_suggestion() {
101+
cx.unknown_key(
102+
param_span,
103+
param.path().to_string(),
104+
if features.deprecated_suggestion() {
106105
&["since", "note", "suggestion"]
107106
} else {
108107
&["since", "note"]
109108
},
110-
});
109+
);
111110
return None;
112111
}
113112
}

compiler/rustc_attr_parsing/src/attributes/inline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
2929
return None;
3030
};
3131

32-
match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
32+
match l.meta_item().and_then(|i| i.path().word_sym()) {
3333
Some(sym::always) => {
3434
Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
3535
}

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_attr_data_structures::{
66
};
77
use rustc_errors::ErrorGuaranteed;
88
use rustc_feature::{AttributeTemplate, template};
9-
use rustc_span::{Span, Symbol, sym};
9+
use rustc_span::{Ident, Span, Symbol, sym};
1010

1111
use super::util::parse_version;
1212
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
@@ -217,23 +217,18 @@ fn insert_value_into_option_or_error<S: Stage>(
217217
cx: &AcceptContext<'_, '_, S>,
218218
param: &MetaItemParser<'_>,
219219
item: &mut Option<Symbol>,
220+
name: Ident,
220221
) -> Option<()> {
221222
if item.is_some() {
222-
cx.emit_err(session_diagnostics::MultipleItem {
223-
span: param.span(),
224-
item: param.path().to_string(),
225-
});
223+
cx.duplicate_key(name.span, name.name);
226224
None
227225
} else if let Some(v) = param.args().name_value()
228226
&& let Some(s) = v.value_as_str()
229227
{
230228
*item = Some(s);
231229
Some(())
232230
} else {
233-
cx.emit_err(session_diagnostics::IncorrectMetaItem {
234-
span: param.span(),
235-
suggestion: None,
236-
});
231+
cx.expected_name_value(param.span(), Some(name.name));
237232
None
238233
}
239234
}
@@ -259,9 +254,14 @@ pub(crate) fn parse_stability<S: Stage>(
259254
return None;
260255
};
261256

262-
match param.path().word_sym() {
263-
Some(sym::feature) => insert_value_into_option_or_error(cx, &param, &mut feature)?,
264-
Some(sym::since) => insert_value_into_option_or_error(cx, &param, &mut since)?,
257+
let word = param.path().word();
258+
match word.map(|i| i.name) {
259+
Some(sym::feature) => {
260+
insert_value_into_option_or_error(cx, &param, &mut feature, word.unwrap())?
261+
}
262+
Some(sym::since) => {
263+
insert_value_into_option_or_error(cx, &param, &mut since, word.unwrap())?
264+
}
265265
_ => {
266266
cx.emit_err(session_diagnostics::UnknownMetaItem {
267267
span: param_span,
@@ -327,11 +327,16 @@ pub(crate) fn parse_unstability<S: Stage>(
327327
return None;
328328
};
329329

330-
match param.path().word_sym() {
331-
Some(sym::feature) => insert_value_into_option_or_error(cx, &param, &mut feature)?,
332-
Some(sym::reason) => insert_value_into_option_or_error(cx, &param, &mut reason)?,
330+
let word = param.path().word();
331+
match word.map(|i| i.name) {
332+
Some(sym::feature) => {
333+
insert_value_into_option_or_error(cx, &param, &mut feature, word.unwrap())?
334+
}
335+
Some(sym::reason) => {
336+
insert_value_into_option_or_error(cx, &param, &mut reason, word.unwrap())?
337+
}
333338
Some(sym::issue) => {
334-
insert_value_into_option_or_error(cx, &param, &mut issue)?;
339+
insert_value_into_option_or_error(cx, &param, &mut issue, word.unwrap())?;
335340

336341
// These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item
337342
// is a name/value pair string literal.
@@ -361,7 +366,7 @@ pub(crate) fn parse_unstability<S: Stage>(
361366
is_soft = true;
362367
}
363368
Some(sym::implied_by) => {
364-
insert_value_into_option_or_error(cx, &param, &mut implied_by)?
369+
insert_value_into_option_or_error(cx, &param, &mut implied_by, word.unwrap())?
365370
}
366371
_ => {
367372
cx.emit_err(session_diagnostics::UnknownMetaItem {

compiler/rustc_attr_parsing/src/attributes/transparency.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
2222
template!(NameValueStr: "transparent|semitransparent|opaque");
2323

2424
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
25-
match args.name_value().and_then(|nv| nv.value_as_str()) {
25+
let Some(nv) = args.name_value() else {
26+
cx.expected_name_value(cx.attr_span, None);
27+
return None;
28+
};
29+
match nv.value_as_str() {
2630
Some(sym::transparent) => Some(Transparency::Transparent),
2731
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
2832
Some(sym::opaque) => Some(Transparency::Opaque),
29-
Some(other) => {
30-
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
33+
Some(_) => {
34+
cx.expected_specific_argument_strings(
35+
nv.value_span,
36+
vec!["transparent", "semitransparent", "opaque"],
37+
);
3138
None
3239
}
3340
None => None,

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::attributes::stability::{
2626
use crate::attributes::transparency::TransparencyParser;
2727
use crate::attributes::{AttributeParser as _, Combine, Single};
2828
use crate::parser::{ArgParser, MetaItemParser};
29-
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason};
29+
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
3030

3131
macro_rules! group_type {
3232
($stage: ty) => {
@@ -208,8 +208,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
208208
(self.emit_lint)(AttributeLint { id, span, kind: lint });
209209
}
210210

211+
pub(crate) fn unknown_key(
212+
&self,
213+
span: Span,
214+
found: String,
215+
options: &'static [&'static str],
216+
) -> ErrorGuaranteed {
217+
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
218+
}
219+
211220
pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed {
212-
// 539?
213221
self.emit_err(AttributeParseError {
214222
span,
215223
attr_span: self.attr_span,
@@ -219,12 +227,40 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
219227
})
220228
}
221229

222-
// pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed {
223-
//
224-
// }
230+
pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
231+
self.emit_err(AttributeParseError {
232+
span,
233+
attr_span: self.attr_span,
234+
template: self.template.clone(),
235+
attribute: self.attr_path.clone(),
236+
reason: AttributeParseErrorReason::ExpectedList,
237+
})
238+
}
239+
240+
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
241+
/// a nicer error message talking about the specific name that was found lacking a value.
242+
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
243+
self.emit_err(AttributeParseError {
244+
span,
245+
attr_span: self.attr_span,
246+
template: self.template.clone(),
247+
attribute: self.attr_path.clone(),
248+
reason: AttributeParseErrorReason::ExpectedNameValue(name),
249+
})
250+
}
251+
252+
/// emit an error that a `name = value` pair was found where that name was already seen.
253+
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
254+
self.emit_err(AttributeParseError {
255+
span,
256+
attr_span: self.attr_span,
257+
template: self.template.clone(),
258+
attribute: self.attr_path.clone(),
259+
reason: AttributeParseErrorReason::DuplicateKey(key),
260+
})
261+
}
225262

226263
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
227-
// E534?
228264
self.emit_err(AttributeParseError {
229265
span,
230266
attr_span: self.attr_span,
@@ -237,15 +273,34 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
237273
pub(crate) fn expected_specific_argument(
238274
&self,
239275
span: Span,
240-
options: Vec<&'static str>,
276+
possibilities: Vec<&'static str>,
277+
) -> 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::ExpectedSpecificArgument {
284+
possibilities,
285+
strings: false,
286+
},
287+
})
288+
}
289+
290+
pub(crate) fn expected_specific_argument_strings(
291+
&self,
292+
span: Span,
293+
possibilities: Vec<&'static str>,
241294
) -> ErrorGuaranteed {
242-
// E535?
243295
self.emit_err(AttributeParseError {
244296
span,
245297
attr_span: self.attr_span,
246298
template: self.template.clone(),
247299
attribute: self.attr_path.clone(),
248-
reason: AttributeParseErrorReason::ExpectedSpecificArgument(options),
300+
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
301+
possibilities,
302+
strings: true,
303+
},
249304
})
250305
}
251306
}

0 commit comments

Comments
 (0)