Skip to content

Commit ba8a3e2

Browse files
committed
fix bugs in inline/force_inline and diagnostics of all attr parsers
1 parent 3c463b3 commit ba8a3e2

31 files changed

+578
-239
lines changed

compiler/rustc_attr_parsing/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ attr_parsing_expects_feature_list =
2323
attr_parsing_expects_features =
2424
`{$name}` expects feature names
2525
26+
attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
27+
[1] attribute must be of the form {$suggestions}
28+
*[other] valid forms for the attribute are {$suggestions}
29+
}
2630
attr_parsing_incorrect_meta_item = expected a quoted string literal
2731
attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
2832
@@ -136,6 +140,7 @@ attr_parsing_unused_duplicate =
136140
.suggestion = remove this attribute
137141
.note = attribute also specified here
138142
.warn = {-passes_previously_accepted}
143+
139144
attr_parsing_unused_multiple =
140145
multiple `{$name}` attributes
141146
.suggestion = remove this attribute

compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::iter;
22

33
use rustc_attr_data_structures::AttributeKind;
4+
use rustc_feature::{AttributeTemplate, template};
45
use rustc_span::{Span, Symbol, sym};
56

67
use super::{CombineAttributeParser, ConvertFn};
@@ -13,6 +14,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
1314
const PATH: &[rustc_span::Symbol] = &[sym::allow_internal_unstable];
1415
type Item = (Symbol, Span);
1516
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
17+
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
1618

1719
fn extend<'c>(
1820
cx: &'c mut AcceptContext<'_, '_, S>,
@@ -29,6 +31,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
2931
const PATH: &[rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable];
3032
type Item = Symbol;
3133
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
34+
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
3235

3336
fn extend<'c>(
3437
cx: &'c mut AcceptContext<'_, '_, S>,

compiler/rustc_attr_parsing/src/attributes/confusables.rs

+34-29
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_attr_data_structures::AttributeKind;
2+
use rustc_feature::template;
23
use rustc_span::{Span, Symbol, sym};
34
use thin_vec::ThinVec;
45

@@ -13,37 +14,41 @@ pub(crate) struct ConfusablesParser {
1314
}
1415

1516
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
16-
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
17-
let Some(list) = args.list() else {
18-
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
19-
// NOTE: currently subsequent attributes are silently ignored using
20-
// tcx.get_attr().
21-
return;
22-
};
23-
24-
if list.is_empty() {
25-
cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
26-
}
27-
28-
for param in list.mixed() {
29-
let span = param.span();
30-
31-
let Some(lit) = param.lit() else {
32-
cx.emit_err(session_diagnostics::IncorrectMetaItem {
33-
span,
34-
suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
35-
lo: span.shrink_to_lo(),
36-
hi: span.shrink_to_hi(),
37-
}),
38-
});
39-
continue;
17+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
18+
&[sym::rustc_confusables],
19+
template!(List: r#""name1", "name2", ..."#),
20+
|this, cx, args| {
21+
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().
25+
return;
4026
};
4127

42-
this.confusables.push(lit.symbol);
43-
}
44-
45-
this.first_span.get_or_insert(cx.attr_span);
46-
})];
28+
if list.is_empty() {
29+
cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
30+
}
31+
32+
for param in list.mixed() {
33+
let span = param.span();
34+
35+
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+
});
43+
continue;
44+
};
45+
46+
this.confusables.push(lit.symbol);
47+
}
48+
49+
this.first_span.get_or_insert(cx.attr_span);
50+
},
51+
)];
4752

4853
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
4954
if self.confusables.is_empty() {

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
2+
use rustc_feature::{AttributeTemplate, template};
23
use rustc_span::symbol::Ident;
34
use rustc_span::{Span, Symbol, sym};
45

@@ -49,6 +50,11 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
4950
const PATH: &[rustc_span::Symbol] = &[sym::deprecated];
5051
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
5152
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
53+
const TEMPLATE: AttributeTemplate = template!(
54+
Word,
55+
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
56+
NameValueStr: "reason"
57+
);
5258

5359
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
5460
let features = cx.features();

compiler/rustc_attr_parsing/src/attributes/inline.rs

+35-15
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,31 @@
33
// SingleAttributeParser which is what we have two of here.
44

55
use rustc_attr_data_structures::{AttributeKind, InlineAttr};
6-
use rustc_errors::{E0534, E0535, struct_span_code_err};
6+
use rustc_errors::DiagArgValue;
7+
use rustc_feature::{AttributeTemplate, template};
8+
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
79
use rustc_span::sym;
810

911
use super::{AcceptContext, AttributeOrder, OnDuplicate};
1012
use crate::attributes::SingleAttributeParser;
1113
use crate::context::Stage;
1214
use crate::parser::ArgParser;
13-
use crate::session_diagnostics::IncorrectMetaItem;
15+
use crate::session_diagnostics::IllFormedAttributeInput;
1416

1517
pub(crate) struct InlineParser;
1618

1719
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
1820
const PATH: &'static [rustc_span::Symbol] = &[sym::inline];
1921
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
2022
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
23+
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
2124

2225
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
2326
match args {
2427
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
2528
ArgParser::List(list) => {
2629
let Some(l) = list.single() else {
27-
struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument")
28-
.emit();
30+
cx.expected_single_argument(list.span);
2931
return None;
3032
};
3133

@@ -37,17 +39,25 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
3739
Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
3840
}
3941
_ => {
40-
struct_span_code_err!(cx.dcx(), l.span(), E0535, "invalid argument")
41-
.with_help("valid inline arguments are `always` and `never`")
42-
.emit();
42+
cx.expected_specific_argument(l.span(), vec!["always", "never"]);
4343
return None;
4444
}
4545
}
4646
}
4747
ArgParser::NameValue(_) => {
48-
// silently ignored, we warn somewhere else.
49-
// FIXME(jdonszelmann): that warning *should* go here.
50-
None
48+
let suggestions =
49+
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
50+
cx.emit_lint(
51+
ILL_FORMED_ATTRIBUTE_INPUT,
52+
cx.attr_span,
53+
IllFormedAttributeInput {
54+
num_suggestions: suggestions.len(),
55+
suggestions: DiagArgValue::StrListSepByAnd(
56+
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
57+
),
58+
},
59+
);
60+
return None;
5161
}
5262
}
5363
}
@@ -59,21 +69,31 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
5969
const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_force_inline];
6070
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
6171
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
72+
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
6273

6374
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
6475
let reason = match args {
6576
ArgParser::NoArgs => None,
6677
ArgParser::List(list) => {
67-
cx.emit_err(IncorrectMetaItem { span: list.span, suggestion: None });
68-
return None;
78+
let Some(l) = list.single() else {
79+
cx.expected_single_argument(list.span);
80+
return None;
81+
};
82+
83+
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
84+
cx.expected_string_literal(l.span());
85+
return None;
86+
};
87+
88+
Some(reason)
6989
}
7090
ArgParser::NameValue(v) => {
71-
let Some(str) = v.value_as_str() else {
72-
cx.emit_err(IncorrectMetaItem { span: v.value_span, suggestion: None });
91+
let Some(reason) = v.value_as_str() else {
92+
cx.expected_string_literal(v.value_span);
7393
return None;
7494
};
7595

76-
Some(str)
96+
Some(reason)
7797
}
7898
};
7999

compiler/rustc_attr_parsing/src/attributes/mod.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use std::marker::PhantomData;
1818

1919
use rustc_attr_data_structures::AttributeKind;
20+
use rustc_feature::AttributeTemplate;
2021
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
2122
use rustc_span::{Span, Symbol};
2223
use thin_vec::ThinVec;
@@ -36,7 +37,8 @@ pub(crate) mod transparency;
3637
pub(crate) mod util;
3738

3839
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
39-
type AcceptMapping<T, S> = &'static [(&'static [rustc_span::Symbol], AcceptFn<T, S>)];
40+
type AcceptMapping<T, S> =
41+
&'static [(&'static [rustc_span::Symbol], AttributeTemplate, AcceptFn<T, S>)];
4042

4143
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
4244
///
@@ -79,6 +81,9 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
7981
const ATTRIBUTE_ORDER: AttributeOrder;
8082
const ON_DUPLICATE: OnDuplicate<S>;
8183

84+
/// The template this attribute parser should implement. Used for diagnostics.
85+
const TEMPLATE: AttributeTemplate;
86+
8287
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
8388
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
8489
}
@@ -95,8 +100,10 @@ impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
95100
}
96101

97102
impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
98-
const ATTRIBUTES: AcceptMapping<Self, S> =
99-
&[(T::PATH, |group: &mut Single<T, S>, cx, args| {
103+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
104+
T::PATH,
105+
<T as SingleAttributeParser<S>>::TEMPLATE,
106+
|group: &mut Single<T, S>, cx, args| {
100107
if let Some(pa) = T::convert(cx, args) {
101108
match T::ATTRIBUTE_ORDER {
102109
// keep the first and report immediately. ignore this attribute
@@ -117,7 +124,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
117124

118125
group.1 = Some((pa, cx.attr_span));
119126
}
120-
})];
127+
},
128+
)];
121129

122130
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
123131
Some(self.1?.0)
@@ -216,6 +224,9 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
216224
type Item;
217225
const CONVERT: ConvertFn<Self::Item>;
218226

227+
/// The template this attribute parser should implement. Used for diagnostics.
228+
const TEMPLATE: AttributeTemplate;
229+
219230
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
220231
fn extend<'c>(
221232
cx: &'c mut AcceptContext<'_, '_, S>,
@@ -235,8 +246,11 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
235246
}
236247

237248
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
238-
const ATTRIBUTES: AcceptMapping<Self, S> =
239-
&[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
249+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
250+
T::PATH,
251+
<T as CombineAttributeParser<S>>::TEMPLATE,
252+
|group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
253+
)];
240254

241255
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
242256
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }

compiler/rustc_attr_parsing/src/attributes/repr.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_abi::Align;
22
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
33
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
4+
use rustc_feature::{AttributeTemplate, template};
45
use rustc_span::{Span, Symbol, sym};
56

67
use super::{CombineAttributeParser, ConvertFn};
@@ -23,6 +24,8 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
2324
type Item = (ReprAttr, Span);
2425
const PATH: &[rustc_span::Symbol] = &[sym::repr];
2526
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
27+
// FIXME(jdonszelmann): never used
28+
const TEMPLATE: AttributeTemplate = template!(List: "C");
2629

2730
fn extend<'c>(
2831
cx: &'c mut AcceptContext<'_, '_, S>,

0 commit comments

Comments
 (0)