Skip to content

Commit 1bb3352

Browse files
committed
Auto merge of #138165 - jdonszelmann:inline, r=oli-obk
Rewrite `inline` attribute parser to use new infrastructure and improve diagnostics for all parsed attributes r? `@oli-obk` This PR: - creates a new parser for inline attributes - creates consistent error messages and error codes between attribute parsers; inline and others - as such changes a few error messages for other attributes to be (in my eyes) much more consistent - tests ast-lowering lints introduced by #138164 since this is now useful for the first time - Coalesce some useless error codes Builds on top of #138164 Closes #137950
2 parents 27733d4 + 81f8b57 commit 1bb3352

File tree

66 files changed

+1189
-647
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1189
-647
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use thin_vec::ThinVec;
88

99
use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
1010

11-
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
11+
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
1212
pub enum InlineAttr {
1313
None,
1414
Hint,
@@ -221,6 +221,9 @@ pub enum AttributeKind {
221221
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
222222
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
223223

224+
/// Represents `#[inline]` and `#[rustc_force_inline]`.
225+
Inline(InlineAttr, Span),
226+
224227
/// Represents `#[rustc_macro_transparency]`.
225228
MacroTransparency(Transparency),
226229

compiler/rustc_attr_data_structures/src/lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ pub struct AttributeLint<Id> {
1111
#[derive(Clone, Debug, HashStable_Generic)]
1212
pub enum AttributeLintKind {
1313
UnusedDuplicate { this: Span, other: Span, warning: bool },
14+
IllFormedAttributeInput { suggestions: Vec<String> },
1415
}

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ attr_parsing_expects_feature_list =
2323
attr_parsing_expects_features =
2424
`{$name}` expects feature names
2525
26-
attr_parsing_incorrect_meta_item = expected a quoted string literal
27-
attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
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+
}
2830
2931
attr_parsing_incorrect_repr_format_align_one_arg =
3032
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
@@ -81,9 +83,6 @@ attr_parsing_missing_note =
8183
attr_parsing_missing_since =
8284
missing 'since'
8385
84-
attr_parsing_multiple_item =
85-
multiple '{$item}' items
86-
8786
attr_parsing_multiple_stability_levels =
8887
multiple stability levels
8988
@@ -122,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean =
122121
literal in `cfg` predicate value must be a boolean
123122
attr_parsing_unsupported_literal_cfg_string =
124123
literal in `cfg` predicate value must be a string
125-
attr_parsing_unsupported_literal_deprecated_kv_pair =
126-
item in `deprecated` must be a key/value pair
127-
attr_parsing_unsupported_literal_deprecated_string =
128-
literal in `deprecated` value must be a string
129124
attr_parsing_unsupported_literal_generic =
130125
unsupported literal
131126
attr_parsing_unsupported_literal_suggestion =
@@ -136,6 +131,7 @@ attr_parsing_unused_duplicate =
136131
.suggestion = remove this attribute
137132
.note = attribute also specified here
138133
.warn = {-passes_previously_accepted}
134+
139135
attr_parsing_unused_multiple =
140136
multiple `{$name}` attributes
141137
.suggestion = remove this attribute

compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs

Lines changed: 3 additions & 0 deletions
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: &[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: &[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

Lines changed: 25 additions & 28 deletions
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,33 @@ 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+
cx.expected_list(cx.attr_span);
23+
return;
4024
};
4125

42-
this.confusables.push(lit.symbol);
43-
}
26+
if list.is_empty() {
27+
cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
28+
}
29+
30+
for param in list.mixed() {
31+
let span = param.span();
32+
33+
let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
34+
cx.expected_string_literal(span, param.lit());
35+
continue;
36+
};
37+
38+
this.confusables.push(lit);
39+
}
4440

45-
this.first_span.get_or_insert(cx.attr_span);
46-
})];
41+
this.first_span.get_or_insert(cx.attr_span);
42+
},
43+
)];
4744

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

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
2+
use rustc_feature::{AttributeTemplate, template};
23
use rustc_span::{Span, Symbol, sym};
34

45
use super::util::parse_version;
56
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
67
use crate::context::{AcceptContext, Stage};
78
use crate::parser::ArgParser;
89
use crate::session_diagnostics;
9-
use crate::session_diagnostics::UnsupportedLiteralReason;
1010

1111
pub(crate) struct DeprecationParser;
1212

@@ -18,25 +18,18 @@ fn get<S: Stage>(
1818
item: &Option<Symbol>,
1919
) -> Option<Symbol> {
2020
if item.is_some() {
21-
cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() });
21+
cx.duplicate_key(param_span, name);
2222
return None;
2323
}
2424
if let Some(v) = arg.name_value() {
2525
if let Some(value_str) = v.value_as_str() {
2626
Some(value_str)
2727
} else {
28-
let lit = v.value_as_lit();
29-
cx.emit_err(session_diagnostics::UnsupportedLiteral {
30-
span: v.value_span,
31-
reason: UnsupportedLiteralReason::DeprecatedString,
32-
is_bytestr: lit.kind.is_bytestr(),
33-
start_point_span: cx.sess().source_map().start_point(lit.span),
34-
});
28+
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
3529
None
3630
}
3731
} else {
38-
// FIXME(jdonszelmann): suggestion?
39-
cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
32+
cx.expected_name_value(param_span, Some(name));
4033
None
4134
}
4235
}
@@ -45,6 +38,11 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
4538
const PATH: &[Symbol] = &[sym::deprecated];
4639
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
4740
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
41+
const TEMPLATE: AttributeTemplate = template!(
42+
Word,
43+
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
44+
NameValueStr: "reason"
45+
);
4846

4947
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
5048
let features = cx.features();
@@ -55,57 +53,60 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
5553

5654
let is_rustc = features.staged_api();
5755

58-
if let Some(value) = args.name_value()
59-
&& let Some(value_str) = value.value_as_str()
60-
{
61-
note = Some(value_str)
62-
} else if let Some(list) = args.list() {
63-
for param in list.mixed() {
64-
let param_span = param.span();
65-
let Some(param) = param.meta_item() else {
66-
cx.emit_err(session_diagnostics::UnsupportedLiteral {
67-
span: param_span,
68-
reason: UnsupportedLiteralReason::DeprecatedKvPair,
69-
is_bytestr: false,
70-
start_point_span: cx.sess().source_map().start_point(param_span),
71-
});
72-
return None;
73-
};
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+
};
7466

75-
let ident_name = param.path().word_sym();
67+
let ident_name = param.path().word_sym();
7668

77-
match ident_name {
78-
Some(name @ sym::since) => {
79-
since = Some(get(cx, name, param_span, param.args(), &since)?);
80-
}
81-
Some(name @ sym::note) => {
82-
note = Some(get(cx, name, param_span, param.args(), &note)?);
83-
}
84-
Some(name @ sym::suggestion) => {
85-
if !features.deprecated_suggestion() {
86-
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
87-
span: param_span,
88-
is_nightly: cx.sess().is_nightly_build(),
89-
details: (),
90-
});
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)?);
9175
}
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+
}
9284

93-
suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
94-
}
95-
_ => {
96-
cx.emit_err(session_diagnostics::UnknownMetaItem {
97-
span: param_span,
98-
item: param.path().to_string(),
99-
expected: if features.deprecated_suggestion() {
100-
&["since", "note", "suggestion"]
101-
} else {
102-
&["since", "note"]
103-
},
104-
});
105-
return None;
85+
suggestion =
86+
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
87+
}
88+
_ => {
89+
cx.unknown_key(
90+
param.span(),
91+
param.path().to_string(),
92+
if features.deprecated_suggestion() {
93+
&["since", "note", "suggestion"]
94+
} else {
95+
&["since", "note"]
96+
},
97+
);
98+
return None;
99+
}
106100
}
107101
}
108102
}
103+
ArgParser::NameValue(v) => {
104+
let Some(value) = v.value_as_str() else {
105+
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
106+
return None;
107+
};
108+
note = Some(value);
109+
}
109110
}
110111

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

compiler/rustc_attr_parsing/src/attributes/inline.rs

Lines changed: 4 additions & 4 deletions
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
}
@@ -63,7 +63,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
6363
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
6464
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
6565

66-
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
66+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
6767
let reason = match args {
6868
ArgParser::NoArgs => None,
6969
ArgParser::List(list) => {
@@ -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/lint_helpers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_attr_data_structures::AttributeKind;
2+
use rustc_feature::{AttributeTemplate, template};
23
use rustc_span::{Symbol, sym};
34

45
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
@@ -9,10 +10,9 @@ pub(crate) struct AsPtrParser;
910

1011
impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
1112
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
12-
1313
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
14-
1514
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
15+
const TEMPLATE: AttributeTemplate = template!(Word);
1616

1717
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
1818
// FIXME: check that there's no args (this is currently checked elsewhere)

0 commit comments

Comments
 (0)