@@ -2,7 +2,10 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
2
2
use rustc_session:: parse:: feature_err;
3
3
4
4
use super :: prelude:: * ;
5
- use crate :: session_diagnostics:: { NakedFunctionIncompatibleAttribute , NullOnExport } ;
5
+ use crate :: session_diagnostics:: {
6
+ NakedFunctionIncompatibleAttribute , NullOnExport , NullOnObjcClass , NullOnObjcSelector ,
7
+ ObjcClassExpectedStringLiteral , ObjcSelectorExpectedStringLiteral ,
8
+ } ;
6
9
7
10
pub ( crate ) struct OptimizeParser ;
8
11
@@ -150,6 +153,70 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
150
153
}
151
154
}
152
155
156
+ pub ( crate ) struct ObjcClassParser ;
157
+
158
+ impl < S : Stage > SingleAttributeParser < S > for ObjcClassParser {
159
+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_class] ;
160
+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
161
+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
162
+ const ALLOWED_TARGETS : AllowedTargets =
163
+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
164
+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "ClassName" ) ;
165
+
166
+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
167
+ let Some ( nv) = args. name_value ( ) else {
168
+ cx. expected_name_value ( cx. attr_span , None ) ;
169
+ return None ;
170
+ } ;
171
+ let Some ( classname) = nv. value_as_str ( ) else {
172
+ // `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
173
+ // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
174
+ // Use a custom error message instead.
175
+ cx. emit_err ( ObjcClassExpectedStringLiteral { span : nv. value_span } ) ;
176
+ return None ;
177
+ } ;
178
+ if classname. as_str ( ) . contains ( '\0' ) {
179
+ // `#[rustc_objc_class = ...]` will be converted to a null-terminated string,
180
+ // so it may not contain any null characters.
181
+ cx. emit_err ( NullOnObjcClass { span : nv. value_span } ) ;
182
+ return None ;
183
+ }
184
+ Some ( AttributeKind :: ObjcClass { classname, span : cx. attr_span } )
185
+ }
186
+ }
187
+
188
+ pub ( crate ) struct ObjcSelectorParser ;
189
+
190
+ impl < S : Stage > SingleAttributeParser < S > for ObjcSelectorParser {
191
+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_selector] ;
192
+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
193
+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
194
+ const ALLOWED_TARGETS : AllowedTargets =
195
+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
196
+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "methodName" ) ;
197
+
198
+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
199
+ let Some ( nv) = args. name_value ( ) else {
200
+ cx. expected_name_value ( cx. attr_span , None ) ;
201
+ return None ;
202
+ } ;
203
+ let Some ( methname) = nv. value_as_str ( ) else {
204
+ // `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
205
+ // inside a standard library macro, but `cx.expected_string_literal` exposes too much.
206
+ // Use a custom error message instead.
207
+ cx. emit_err ( ObjcSelectorExpectedStringLiteral { span : nv. value_span } ) ;
208
+ return None ;
209
+ } ;
210
+ if methname. as_str ( ) . contains ( '\0' ) {
211
+ // `#[rustc_objc_selector = ...]` will be converted to a null-terminated string,
212
+ // so it may not contain any null characters.
213
+ cx. emit_err ( NullOnObjcSelector { span : nv. value_span } ) ;
214
+ return None ;
215
+ }
216
+ Some ( AttributeKind :: ObjcSelector { methname, span : cx. attr_span } )
217
+ }
218
+ }
219
+
153
220
#[ derive( Default ) ]
154
221
pub ( crate ) struct NakedParser {
155
222
span : Option < Span > ,
0 commit comments