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