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