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}