@@ -2,7 +2,9 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
22use rustc_session:: parse:: feature_err;
33
44use super :: prelude:: * ;
5- use crate :: session_diagnostics:: { NakedFunctionIncompatibleAttribute , NullOnExport } ;
5+ use crate :: session_diagnostics:: {
6+ NakedFunctionIncompatibleAttribute , NullOnExport , NullOnObjcClass , NullOnObjcSelector ,
7+ } ;
68
79pub ( crate ) struct OptimizeParser ;
810
@@ -150,6 +152,64 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
150152 }
151153}
152154
155+ pub ( crate ) struct ObjcClassParser ;
156+
157+ impl < S : Stage > SingleAttributeParser < S > for ObjcClassParser {
158+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_class] ;
159+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
160+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
161+ const ALLOWED_TARGETS : AllowedTargets =
162+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
163+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "ClassName" ) ;
164+
165+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
166+ let Some ( nv) = args. name_value ( ) else {
167+ cx. expected_name_value ( cx. attr_span , None ) ;
168+ return None ;
169+ } ;
170+ let Some ( classname) = nv. value_as_str ( ) else {
171+ cx. expected_string_literal ( nv. value_span , Some ( nv. value_as_lit ( ) ) ) ;
172+ return None ;
173+ } ;
174+ if classname. as_str ( ) . contains ( '\0' ) {
175+ // `#[rustc_objc_class = ...]` will be converted to a null-terminated string,
176+ // so it may not contain any null characters.
177+ cx. emit_err ( NullOnObjcClass { span : cx. attr_span } ) ;
178+ return None ;
179+ }
180+ Some ( AttributeKind :: ObjcClass { classname, span : cx. attr_span } )
181+ }
182+ }
183+
184+ pub ( crate ) struct ObjcSelectorParser ;
185+
186+ impl < S : Stage > SingleAttributeParser < S > for ObjcSelectorParser {
187+ const PATH : & [ rustc_span:: Symbol ] = & [ sym:: rustc_objc_selector] ;
188+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepInnermost ;
189+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: Error ;
190+ const ALLOWED_TARGETS : AllowedTargets =
191+ AllowedTargets :: AllowList ( & [ Allow ( Target :: ForeignStatic ) ] ) ;
192+ const TEMPLATE : AttributeTemplate = template ! ( NameValueStr : "methodName" ) ;
193+
194+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser < ' _ > ) -> Option < AttributeKind > {
195+ let Some ( nv) = args. name_value ( ) else {
196+ cx. expected_name_value ( cx. attr_span , None ) ;
197+ return None ;
198+ } ;
199+ let Some ( methname) = nv. value_as_str ( ) else {
200+ cx. expected_string_literal ( nv. value_span , Some ( nv. value_as_lit ( ) ) ) ;
201+ return None ;
202+ } ;
203+ if methname. as_str ( ) . contains ( '\0' ) {
204+ // `#[rustc_objc_selector = ...]` will be converted to a null-terminated string,
205+ // so it may not contain any null characters.
206+ cx. emit_err ( NullOnObjcSelector { span : cx. attr_span } ) ;
207+ return None ;
208+ }
209+ Some ( AttributeKind :: ObjcSelector { methname, span : cx. attr_span } )
210+ }
211+ }
212+
153213#[ derive( Default ) ]
154214pub ( crate ) struct NakedParser {
155215 span : Option < Span > ,
0 commit comments