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 SingleAttributeParser for IgnoreParser {
9 const PATH: &[Symbol] = &[sym::ignore];
10 const ON_DUPLICATE: OnDuplicate = 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<'_, '_>, 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.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
26 return None;
27 };
28 Some(str_value)
29 }
30 ArgParser::List(list) => {
31 let help =
32 list.as_single().and_then(|item| item.meta_item()).and_then(|item| {
33 item.args().as_no_args().ok()?;
34 Some(item.path().to_string())
35 });
36 cx.adcx().warn_ill_formed_attribute_input_with_help(
37 ILL_FORMED_ATTRIBUTE_INPUT,
38 help,
39 );
40 return None;
41 }
42 },
43 })
44 }
45}
46
47pub(crate) struct ShouldPanicParser;
48
49impl SingleAttributeParser for ShouldPanicParser {
50 const PATH: &[Symbol] = &[sym::should_panic];
51 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
52 const ALLOWED_TARGETS: AllowedTargets =
53 AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
54 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!(
55 Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
56 "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
57 );
58
59 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
60 Some(AttributeKind::ShouldPanic {
61 reason: match args {
62 ArgParser::NoArgs => None,
63 ArgParser::NameValue(name_value) => cx.expect_string_literal(name_value),
64 ArgParser::List(list) => {
65 let single = cx.expect_single(list)?;
66 let (ident, arg) =
67 cx.expect_name_value(single, single.span(), Some(sym::expected))?;
68 if ident.name != sym::expected {
69 cx.adcx().expected_specific_argument_strings(list.span, &[sym::expected]);
70 return None;
71 }
72 cx.expect_string_literal(arg)
73 }
74 },
75 })
76 }
77}
78
79pub(crate) struct ReexportTestHarnessMainParser;
80
81impl SingleAttributeParser for ReexportTestHarnessMainParser {
82 const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
83 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
84 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
85
86 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
87 let nv = cx.expect_name_value(
88 args,
89 args.span().unwrap_or(cx.inner_span),
90 Some(sym::reexport_test_harness_main),
91 )?;
92
93 let name = cx.expect_string_literal(nv)?;
94
95 Some(AttributeKind::ReexportTestHarnessMain(name))
96 }
97}
98
99pub(crate) struct RustcAbiParser;
100
101impl SingleAttributeParser for RustcAbiParser {
102 const PATH: &[Symbol] = &[sym::rustc_abi];
103 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]);
104 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
105 Allow(Target::TyAlias),
106 Allow(Target::Fn),
107 Allow(Target::ForeignFn),
108 Allow(Target::Method(MethodKind::Inherent)),
109 Allow(Target::Method(MethodKind::Trait { body: true })),
110 Allow(Target::Method(MethodKind::Trait { body: false })),
111 Allow(Target::Method(MethodKind::TraitImpl)),
112 ]);
113
114 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
115 let Some(args) = args.as_list() else {
116 let attr_span = cx.attr_span;
117 cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::assert_eq, sym::debug]);
118 return None;
119 };
120
121 let arg = cx.expect_single(args)?;
122
123 let mut fail_incorrect_argument =
124 |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
125
126 let Some(arg) = arg.meta_item() else {
127 fail_incorrect_argument(args.span);
128 return None;
129 };
130
131 let kind: RustcAbiAttrKind = match arg.path().word_sym() {
132 Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
133 Some(sym::debug) => RustcAbiAttrKind::Debug,
134 None | Some(_) => {
135 fail_incorrect_argument(arg.span());
136 return None;
137 }
138 };
139
140 Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
141 }
142}
143
144pub(crate) struct RustcDelayedBugFromInsideQueryParser;
145
146impl NoArgsAttributeParser for RustcDelayedBugFromInsideQueryParser {
147 const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
148 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
149 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
150}
151
152pub(crate) struct RustcEvaluateWhereClausesParser;
153
154impl NoArgsAttributeParser for RustcEvaluateWhereClausesParser {
155 const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
156 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
157 Allow(Target::Fn),
158 Allow(Target::Method(MethodKind::Inherent)),
159 Allow(Target::Method(MethodKind::Trait { body: true })),
160 Allow(Target::Method(MethodKind::TraitImpl)),
161 Allow(Target::Method(MethodKind::Trait { body: false })),
162 ]);
163 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
164}
165
166pub(crate) struct TestRunnerParser;
167
168impl SingleAttributeParser for TestRunnerParser {
169 const PATH: &[Symbol] = &[sym::test_runner];
170 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
171 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["path"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["path"]);
172
173 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
174 let single = cx.expect_single_element_list(args, cx.attr_span)?;
175
176 let Some(meta) = single.meta_item() else {
177 cx.adcx().expected_not_literal(single.span());
178 return None;
179 };
180
181 Some(AttributeKind::TestRunner(meta.path().0.clone()))
182 }
183}
184
185pub(crate) struct RustcTestMarkerParser;
186
187impl SingleAttributeParser for RustcTestMarkerParser {
188 const PATH: &[Symbol] = &[sym::rustc_test_marker];
189 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
190 Allow(Target::Const),
191 Allow(Target::Fn),
192 Allow(Target::Static),
193 ]);
194 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["test_path"]),
docs: None,
}template!(NameValueStr: "test_path");
195
196 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
197 let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::rustc_test_marker))?;
198 let value_str = cx.expect_string_literal(name_value)?;
199
200 if value_str.as_str().trim().is_empty() {
201 cx.adcx().expected_non_empty_string_literal(name_value.value_span);
202 return None;
203 }
204
205 Some(AttributeKind::RustcTestMarker(value_str))
206 }
207}