rustc_attr_parsing/attributes/
test_attrs.rs1use rustc_hir::attrs::RustcAbiAttrKind;
2use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
3
4use super::prelude::*;
5
6pub(crate) struct IgnoreParser;
7
8impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
9 const PATH: &[Symbol] = &[sym::ignore];
10 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
11 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
12 const ALLOWED_TARGETS: AllowedTargets =
13 AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
14 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: Some(&["reason"]),
docs: Some("https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"),
}template!(
15 Word, NameValueStr: "reason",
16 "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
17 );
18
19 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
20 Some(AttributeKind::Ignore {
21 span: cx.attr_span,
22 reason: match args {
23 ArgParser::NoArgs => None,
24 ArgParser::NameValue(name_value) => {
25 let Some(str_value) = name_value.value_as_str() else {
26 cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
27 return None;
28 };
29 Some(str_value)
30 }
31 ArgParser::List(_) => {
32 cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
33 return None;
34 }
35 },
36 })
37 }
38}
39
40pub(crate) struct ShouldPanicParser;
41
42impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
43 const PATH: &[Symbol] = &[sym::should_panic];
44 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
45 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
46 const ALLOWED_TARGETS: AllowedTargets =
47 AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
48 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&[r#"expected = "reason""#]),
one_of: &[],
name_value_str: Some(&["reason"]),
docs: Some("https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"),
}template!(
49 Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
50 "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
51 );
52
53 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
54 Some(AttributeKind::ShouldPanic {
55 span: cx.attr_span,
56 reason: match args {
57 ArgParser::NoArgs => None,
58 ArgParser::NameValue(name_value) => {
59 let Some(str_value) = name_value.value_as_str() else {
60 cx.expected_string_literal(
61 name_value.value_span,
62 Some(name_value.value_as_lit()),
63 );
64 return None;
65 };
66 Some(str_value)
67 }
68 ArgParser::List(list) => {
69 let Some(single) = list.single() else {
70 cx.expected_single_argument(list.span);
71 return None;
72 };
73 let Some(single) = single.meta_item() else {
74 cx.expected_name_value(single.span(), Some(sym::expected));
75 return None;
76 };
77 if !single.path().word_is(sym::expected) {
78 cx.expected_specific_argument_strings(list.span, &[sym::expected]);
79 return None;
80 }
81 let Some(nv) = single.args().name_value() else {
82 cx.expected_name_value(single.span(), Some(sym::expected));
83 return None;
84 };
85 let Some(expected) = nv.value_as_str() else {
86 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
87 return None;
88 };
89 Some(expected)
90 }
91 },
92 })
93 }
94}
95
96pub(crate) struct RustcVarianceParser;
97
98impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceParser {
99 const PATH: &[Symbol] = &[sym::rustc_variance];
100 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
101 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
102 Allow(Target::Struct),
103 Allow(Target::Enum),
104 Allow(Target::Union),
105 ]);
106 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance;
107}
108
109pub(crate) struct RustcVarianceOfOpaquesParser;
110
111impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
112 const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques];
113 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
114 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
115 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques;
116}
117
118pub(crate) struct ReexportTestHarnessMainParser;
119
120impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
121 const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
122 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
123 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
124 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
125 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
126
127 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
128 let Some(nv) = args.name_value() else {
129 cx.expected_name_value(
130 args.span().unwrap_or(cx.inner_span),
131 Some(sym::reexport_test_harness_main),
132 );
133 return None;
134 };
135
136 let Some(name) = nv.value_as_str() else {
137 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
138 return None;
139 };
140
141 Some(AttributeKind::ReexportTestHarnessMain(name))
142 }
143}
144
145pub(crate) struct RustcAbiParser;
146
147impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
148 const PATH: &[Symbol] = &[sym::rustc_abi];
149 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
150 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[sym::debug, sym::assert_eq],
name_value_str: None,
docs: None,
}template!(OneOf: &[sym::debug, sym::assert_eq]);
151 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
152 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
153 Allow(Target::TyAlias),
154 Allow(Target::Fn),
155 Allow(Target::ForeignFn),
156 Allow(Target::Method(MethodKind::Inherent)),
157 Allow(Target::Method(MethodKind::Trait { body: true })),
158 Allow(Target::Method(MethodKind::Trait { body: false })),
159 Allow(Target::Method(MethodKind::TraitImpl)),
160 ]);
161
162 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
163 let Some(args) = args.list() else {
164 cx.expected_specific_argument_and_list(cx.attr_span, &[sym::assert_eq, sym::debug]);
165 return None;
166 };
167
168 let Some(arg) = args.single() else {
169 cx.expected_single_argument(cx.attr_span);
170 return None;
171 };
172
173 let fail_incorrect_argument =
174 |span| cx.expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
175
176 let Some(arg) = arg.meta_item() else {
177 fail_incorrect_argument(args.span);
178 return None;
179 };
180
181 let kind: RustcAbiAttrKind = match arg.path().word_sym() {
182 Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
183 Some(sym::debug) => RustcAbiAttrKind::Debug,
184 None | Some(_) => {
185 fail_incorrect_argument(arg.span());
186 return None;
187 }
188 };
189
190 Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
191 }
192}
193
194pub(crate) struct RustcDelayedBugFromInsideQueryParser;
195
196impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser {
197 const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
198 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
199 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
200 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
201}
202
203pub(crate) struct RustcEvaluateWhereClausesParser;
204
205impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
206 const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
207 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
208 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
209 Allow(Target::Fn),
210 Allow(Target::Method(MethodKind::Inherent)),
211 Allow(Target::Method(MethodKind::Trait { body: true })),
212 Allow(Target::Method(MethodKind::TraitImpl)),
213 Allow(Target::Method(MethodKind::Trait { body: false })),
214 ]);
215 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
216}
217
218pub(crate) struct RustcOutlivesParser;
219
220impl<S: Stage> NoArgsAttributeParser<S> for RustcOutlivesParser {
221 const PATH: &[Symbol] = &[sym::rustc_outlives];
222 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
223 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
224 Allow(Target::Struct),
225 Allow(Target::Enum),
226 Allow(Target::Union),
227 Allow(Target::TyAlias),
228 ]);
229 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOutlives;
230}
231
232pub(crate) struct TestRunnerParser;
233
234impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
235 const PATH: &[Symbol] = &[sym::test_runner];
236 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
237 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
238 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
239 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["path"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["path"]);
240
241 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
242 let Some(list) = args.list() else {
243 cx.expected_list(cx.attr_span, args);
244 return None;
245 };
246
247 let Some(single) = list.single() else {
248 cx.expected_single_argument(list.span);
249 return None;
250 };
251
252 let Some(meta) = single.meta_item() else {
253 cx.unexpected_literal(single.span());
254 return None;
255 };
256
257 Some(AttributeKind::TestRunner(meta.path().0.clone()))
258 }
259}
260
261pub(crate) struct RustcTestMarkerParser;
262
263impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
264 const PATH: &[Symbol] = &[sym::rustc_test_marker];
265 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
266 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
267 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
268 Allow(Target::Const),
269 Allow(Target::Fn),
270 Allow(Target::Static),
271 ]);
272 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["test_path"]),
docs: None,
}template!(NameValueStr: "test_path");
273
274 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
275 let Some(name_value) = args.name_value() else {
276 cx.expected_name_value(cx.attr_span, Some(sym::rustc_test_marker));
277 return None;
278 };
279
280 let Some(value_str) = name_value.value_as_str() else {
281 cx.expected_string_literal(name_value.value_span, None);
282 return None;
283 };
284
285 if value_str.as_str().trim().is_empty() {
286 cx.expected_non_empty_string_literal(name_value.value_span);
287 return None;
288 }
289
290 Some(AttributeKind::RustcTestMarker(value_str))
291 }
292}