@@ -11,7 +11,9 @@ use super::{
11
11
use crate :: context:: MaybeWarn :: { Allow , Warn } ;
12
12
use crate :: context:: { AcceptContext , AllowedTargets , FinalizeContext , Stage } ;
13
13
use crate :: parser:: ArgParser ;
14
- use crate :: session_diagnostics:: { NakedFunctionIncompatibleAttribute , NullOnExport } ;
14
+ use crate :: session_diagnostics:: {
15
+ NakedFunctionIncompatibleAttribute , NullOnExport , NullOnObjcClass , NullOnObjcSelector ,
16
+ } ;
15
17
16
18
pub ( crate ) struct OptimizeParser ;
17
19
@@ -157,6 +159,64 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
157
159
}
158
160
}
159
161
162
+ pub ( crate ) struct ObjcClassParser ;
163
+
164
+ impl < S : Stage > SingleAttributeParser < S > for ObjcClassParser {
165
+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_class] ;
166
+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
167
+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
168
+ const ALLOWED_TARGETS : AllowedTargets =
169
+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
170
+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "ClassName" ) ;
171
+
172
+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
173
+ let Some ( nv) = args. name_value ( ) else {
174
+ cx. expected_name_value ( cx. attr_span , None ) ;
175
+ return None ;
176
+ } ;
177
+ let Some ( classname) = nv. value_as_str ( ) else {
178
+ cx. expected_string_literal ( nv. value_span , Some ( nv. value_as_lit ( ) ) ) ;
179
+ return None ;
180
+ } ;
181
+ if classname. as_str ( ) . contains ( '\0' ) {
182
+ // `#[rustc_objc_class = ...]` will be converted to a null-terminated string,
183
+ // so it may not contain any null characters.
184
+ cx. emit_err ( NullOnObjcClass { span : cx. attr_span } ) ;
185
+ return None ;
186
+ }
187
+ Some ( AttributeKind :: ObjcClass { classname, span : cx. attr_span } )
188
+ }
189
+ }
190
+
191
+ pub ( crate ) struct ObjcSelectorParser ;
192
+
193
+ impl < S : Stage > SingleAttributeParser < S > for ObjcSelectorParser {
194
+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_selector] ;
195
+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
196
+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
197
+ const ALLOWED_TARGETS : AllowedTargets =
198
+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
199
+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "methodName" ) ;
200
+
201
+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
202
+ let Some ( nv) = args. name_value ( ) else {
203
+ cx. expected_name_value ( cx. attr_span , None ) ;
204
+ return None ;
205
+ } ;
206
+ let Some ( methname) = nv. value_as_str ( ) else {
207
+ cx. expected_string_literal ( nv. value_span , Some ( nv. value_as_lit ( ) ) ) ;
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 : cx. attr_span } ) ;
214
+ return None ;
215
+ }
216
+ Some ( AttributeKind :: ObjcSelector { methname, span : cx. attr_span } )
217
+ }
218
+ }
219
+
160
220
#[ derive( Default ) ]
161
221
pub ( crate ) struct NakedParser {
162
222
span : Option < Span > ,
0 commit comments