Skip to content

Commit 12a5073

Browse files
committed
use consistent attr errors in all attribute parsers
1 parent c8765fe commit 12a5073

21 files changed

+303
-141
lines changed

Diff for: compiler/rustc_attr_parsing/messages.ftl

-5
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

Diff for: compiler/rustc_attr_parsing/src/attributes/confusables.rs

+2-10
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

Diff for: compiler/rustc_attr_parsing/src/attributes/deprecation.rs

+7-11
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ fn get<S: Stage>(
2020
item: &Option<Symbol>,
2121
) -> Option<Symbol> {
2222
if item.is_some() {
23-
cx.emit_err(session_diagnostics::MultipleItem {
24-
span: param_span,
25-
item: ident.to_string(),
26-
});
23+
cx.duplicate_key(ident.span, ident.name);
2724
return None;
2825
}
2926
if let Some(v) = arg.name_value() {
@@ -40,8 +37,7 @@ fn get<S: Stage>(
4037
None
4138
}
4239
} else {
43-
// FIXME(jdonszelmann): suggestion?
44-
cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
40+
cx.expected_name_value(param_span, Some(ident.name));
4541
None
4642
}
4743
}
@@ -103,15 +99,15 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
10399
suggestion = Some(get(cx, ident, param_span, arg, &suggestion)?);
104100
}
105101
_ => {
106-
cx.emit_err(session_diagnostics::UnknownMetaItem {
107-
span: param_span,
108-
item: ident.to_string(),
109-
expected: if features.deprecated_suggestion() {
102+
cx.unknown_key(
103+
param_span,
104+
ident.to_string(),
105+
if features.deprecated_suggestion() {
110106
&["since", "note", "suggestion"]
111107
} else {
112108
&["since", "note"]
113109
},
114-
});
110+
);
115111
return None;
116112
}
117113
}

Diff for: compiler/rustc_attr_parsing/src/attributes/stability.rs

+18-17
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, kw, sym};
9+
use rustc_span::{Ident, Span, Symbol, sym};
1010

1111
use super::util::parse_version;
1212
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
@@ -76,7 +76,10 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
7676
this.allowed_through_unstable_modules =
7777
Some(match args.name_value().and_then(|i| i.value_as_str()) {
7878
Some(msg) => msg,
79-
None => kw::Empty,
79+
None => {
80+
cx.expected_name_value(cx.attr_span, None);
81+
return;
82+
}
8083
});
8184
},
8285
),
@@ -220,23 +223,18 @@ fn insert_value_into_option_or_error<S: Stage>(
220223
cx: &AcceptContext<'_, '_, S>,
221224
param: &MetaItemParser<'_>,
222225
item: &mut Option<Symbol>,
226+
name: Ident,
223227
) -> Option<()> {
224228
if item.is_some() {
225-
cx.emit_err(session_diagnostics::MultipleItem {
226-
span: param.span(),
227-
item: param.path_without_args().to_string(),
228-
});
229+
cx.duplicate_key(name.span, name.name);
229230
None
230231
} else if let Some(v) = param.args().name_value()
231232
&& let Some(s) = v.value_as_str()
232233
{
233234
*item = Some(s);
234235
Some(())
235236
} else {
236-
cx.emit_err(session_diagnostics::IncorrectMetaItem {
237-
span: param.span(),
238-
suggestion: None,
239-
});
237+
cx.expected_name_value(param.span(), Some(name.name));
240238
None
241239
}
242240
}
@@ -262,9 +260,10 @@ pub(crate) fn parse_stability<S: Stage>(
262260
return None;
263261
};
264262

265-
match param.word_or_empty_without_args().name {
266-
sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature)?,
267-
sym::since => insert_value_into_option_or_error(cx, &param, &mut since)?,
263+
let name = param.word_or_empty_without_args();
264+
match name.name {
265+
sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature, name)?,
266+
sym::since => insert_value_into_option_or_error(cx, &param, &mut since, name)?,
268267
_ => {
269268
cx.emit_err(session_diagnostics::UnknownMetaItem {
270269
span: param_span,
@@ -332,10 +331,10 @@ pub(crate) fn parse_unstability<S: Stage>(
332331

333332
let (word, args) = param.word_or_empty();
334333
match word.name {
335-
sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature)?,
336-
sym::reason => insert_value_into_option_or_error(cx, &param, &mut reason)?,
334+
sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature, word)?,
335+
sym::reason => insert_value_into_option_or_error(cx, &param, &mut reason, word)?,
337336
sym::issue => {
338-
insert_value_into_option_or_error(cx, &param, &mut issue)?;
337+
insert_value_into_option_or_error(cx, &param, &mut issue, word)?;
339338

340339
// These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item
341340
// is a name/value pair string literal.
@@ -364,7 +363,9 @@ pub(crate) fn parse_unstability<S: Stage>(
364363
}
365364
is_soft = true;
366365
}
367-
sym::implied_by => insert_value_into_option_or_error(cx, &param, &mut implied_by)?,
366+
sym::implied_by => {
367+
insert_value_into_option_or_error(cx, &param, &mut implied_by, word)?
368+
}
368369
_ => {
369370
cx.emit_err(session_diagnostics::UnknownMetaItem {
370371
span: param.span(),

Diff for: compiler/rustc_attr_parsing/src/attributes/transparency.rs

+10-3
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: &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::semitransparent) => Some(Transparency::SemiTransparent),
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,

Diff for: compiler/rustc_attr_parsing/src/context.rs

+64-9
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::attributes::stability::{
2727
use crate::attributes::transparency::TransparencyParser;
2828
use crate::attributes::{AttributeParser as _, Combine, Single};
2929
use crate::parser::{ArgParser, MetaItemParser};
30-
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason};
30+
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
3131

3232
macro_rules! group_type {
3333
($stage: ty) => {
@@ -241,8 +241,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
241241
S::emit_lint(self.dcx(), lint, self.target_id, span, diag)
242242
}
243243

244+
pub(crate) fn unknown_key(
245+
&self,
246+
span: Span,
247+
found: String,
248+
options: &'static [&'static str],
249+
) -> ErrorGuaranteed {
250+
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
251+
}
252+
244253
pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed {
245-
// 539?
246254
self.emit_err(AttributeParseError {
247255
span,
248256
attr_span: self.attr_span,
@@ -252,12 +260,40 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
252260
})
253261
}
254262

255-
// pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed {
256-
//
257-
// }
263+
pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
264+
self.emit_err(AttributeParseError {
265+
span,
266+
attr_span: self.attr_span,
267+
template: self.template.clone(),
268+
attribute: self.attr_path.clone(),
269+
reason: AttributeParseErrorReason::ExpectedList,
270+
})
271+
}
272+
273+
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
274+
/// a nicer error message talking about the specific name that was found lacking a value.
275+
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
276+
self.emit_err(AttributeParseError {
277+
span,
278+
attr_span: self.attr_span,
279+
template: self.template.clone(),
280+
attribute: self.attr_path.clone(),
281+
reason: AttributeParseErrorReason::ExpectedNameValue(name),
282+
})
283+
}
284+
285+
/// emit an error that a `name = value` pair was found where that name was already seen.
286+
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
287+
self.emit_err(AttributeParseError {
288+
span,
289+
attr_span: self.attr_span,
290+
template: self.template.clone(),
291+
attribute: self.attr_path.clone(),
292+
reason: AttributeParseErrorReason::DuplicateKey(key),
293+
})
294+
}
258295

259296
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
260-
// E534?
261297
self.emit_err(AttributeParseError {
262298
span,
263299
attr_span: self.attr_span,
@@ -270,15 +306,34 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
270306
pub(crate) fn expected_specific_argument(
271307
&self,
272308
span: Span,
273-
options: Vec<&'static str>,
309+
possibilities: Vec<&'static str>,
310+
) -> ErrorGuaranteed {
311+
self.emit_err(AttributeParseError {
312+
span,
313+
attr_span: self.attr_span,
314+
template: self.template.clone(),
315+
attribute: self.attr_path.clone(),
316+
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
317+
possibilities,
318+
strings: false,
319+
},
320+
})
321+
}
322+
323+
pub(crate) fn expected_specific_argument_strings(
324+
&self,
325+
span: Span,
326+
possibilities: Vec<&'static str>,
274327
) -> ErrorGuaranteed {
275-
// E535?
276328
self.emit_err(AttributeParseError {
277329
span,
278330
attr_span: self.attr_span,
279331
template: self.template.clone(),
280332
attribute: self.attr_path.clone(),
281-
reason: AttributeParseErrorReason::ExpectedSpecificArgument(options),
333+
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
334+
possibilities,
335+
strings: true,
336+
},
282337
})
283338
}
284339
}

0 commit comments

Comments
 (0)