@@ -11,7 +11,9 @@ use super::{
1111use crate :: context:: MaybeWarn :: { Allow , Warn } ;
1212use crate :: context:: { AcceptContext , AllowedTargets , FinalizeContext , Stage } ;
1313use crate :: parser:: ArgParser ;
14- use crate :: session_diagnostics:: { NakedFunctionIncompatibleAttribute , NullOnExport } ;
14+ use crate :: session_diagnostics:: {
15+ NakedFunctionIncompatibleAttribute , NullOnExport , NullOnObjcClass , NullOnObjcSelector ,
16+ } ;
1517
1618pub ( crate ) struct OptimizeParser ;
1719
@@ -157,6 +159,64 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
157159 }
158160}
159161
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+
160220#[ derive( Default ) ]
161221pub ( crate ) struct NakedParser {
162222 span : Option < Span > ,
0 commit comments