@@ -49,13 +49,26 @@ use crate::runtime::Sel;
4949/// - runtime, causing UB (unlikely)
5050///
5151/// The `"unstable-static-sel-inlined"` feature is the even more extreme
52- /// version - it yields the best performance and is closest to real
52+ /// version - it yield better performance and is closer to real
5353/// Objective-C code, but probably won't work unless your code and its
5454/// inlining is written in a very certain way.
5555///
5656/// Enabling LTO greatly increases the chance that these features work.
5757///
58+ /// On Apple/Darwin targets, these limitations can be overcome with the
59+ /// `"unstable-darwin-objc"` feature which uses the nightly-only `darwin_objc`
60+ /// language feature. This experimental language feature implements the
61+ /// Objective-C static selector ABI directly in the Rust compiler and should
62+ /// work in more if not all cases. Using `"unstable-darwin-objc"` requires
63+ /// `darwin_objc` to be enabled in every crate that uses this macro, which can
64+ /// be achieved in `objc2` crates by enabling their own
65+ /// `"unstable-darwin-objc"` features and in your own crates by adding
66+ /// `#![feature(darwin_objc)]`.
67+ ///
68+ /// See [rust-lang/rust#145496] for the tracking issue for the feature.
69+ ///
5870/// [rust-lang/rust#53929]: https://github.com/rust-lang/rust/issues/53929
71+ /// [rust-lang/rust#145496]: https://github.com/rust-lang/rust/issues/145496
5972///
6073///
6174/// # Examples
@@ -177,9 +190,9 @@ macro_rules! __sel_helper {
177190 // Base-case
178191 {
179192 ( $( $parsed_sel: tt) * )
180- } => ( {
193+ } => {
181194 $crate:: __sel_data!( $( $parsed_sel) * )
182- } ) ;
195+ } ;
183196 // Single identifier
184197 {
185198 ( )
@@ -219,7 +232,6 @@ macro_rules! __sel_data {
219232 $crate:: __macros:: concat!(
220233 $crate:: __macros:: stringify!( $first) ,
221234 $( ':' , $( $( $crate:: __macros:: stringify!( $rest) , ) ? ':' , ) * ) ?
222- '\0' ,
223235 )
224236 } ;
225237}
@@ -232,7 +244,21 @@ macro_rules! __sel_inner {
232244 static CACHED_SEL : $crate:: __macros:: CachedSel = $crate:: __macros:: CachedSel :: new( ) ;
233245 #[ allow( unused_unsafe) ]
234246 unsafe {
235- CACHED_SEL . get( $data)
247+ CACHED_SEL . get( $crate:: __macros:: concat!( $data, '\0' ) )
248+ }
249+ } } ;
250+ }
251+
252+ #[ doc( hidden) ]
253+ #[ macro_export]
254+ #[ cfg( all( feature = "unstable-static-sel" , feature = "unstable-darwin-objc" ) ) ]
255+ macro_rules! __sel_inner {
256+ ( $data: expr, $_hash: expr) => { {
257+ let ptr = $crate:: __macros:: core_darwin_objc:: selector!( $data) ;
258+ let ptr = ptr. cast_const( ) . cast:: <$crate:: __macros:: u8 >( ) ;
259+ #[ allow( unused_unsafe) ]
260+ unsafe {
261+ $crate:: runtime:: Sel :: __internal_from_ptr( ptr)
236262 }
237263 } } ;
238264}
@@ -245,7 +271,7 @@ macro_rules! __statics_sel {
245271 ( $data: expr)
246272 ( $hash: expr)
247273 } => {
248- const X : & [ $crate:: __macros:: u8 ] = $data. as_bytes( ) ;
274+ const X : & [ $crate:: __macros:: u8 ] = $crate :: __macros :: concat! ( $ data, '\0' ) . as_bytes( ) ;
249275
250276 /// Clang marks this with LLVM's `unnamed_addr`.
251277 /// See rust-lang/rust#18297
@@ -321,7 +347,8 @@ macro_rules! __statics_sel {
321347#[ macro_export]
322348#[ cfg( all(
323349 feature = "unstable-static-sel" ,
324- not( feature = "unstable-static-sel-inlined" )
350+ not( feature = "unstable-darwin-objc" ) ,
351+ not( feature = "unstable-static-sel-inlined" ) ,
325352) ) ]
326353macro_rules! __sel_inner {
327354 ( $data: expr, $hash: expr) => { {
@@ -353,7 +380,11 @@ macro_rules! __sel_inner {
353380
354381#[ doc( hidden) ]
355382#[ macro_export]
356- #[ cfg( feature = "unstable-static-sel-inlined" ) ]
383+ #[ cfg( all(
384+ feature = "unstable-static-sel" ,
385+ not( feature = "unstable-darwin-objc" ) ,
386+ feature = "unstable-static-sel-inlined" ,
387+ ) ) ]
357388macro_rules! __sel_inner {
358389 ( $data: expr, $hash: expr) => { {
359390 $crate:: __statics_sel! {
@@ -425,30 +456,30 @@ impl CachedSel {
425456
426457#[ inline]
427458pub fn alloc_sel ( ) -> Sel {
428- __sel_inner ! ( "alloc\0 " , "alloc" )
459+ __sel_inner ! ( "alloc" , "alloc" )
429460}
430461
431462#[ inline]
432463pub fn init_sel ( ) -> Sel {
433- __sel_inner ! ( "init\0 " , "init" )
464+ __sel_inner ! ( "init" , "init" )
434465}
435466
436467#[ inline]
437468pub fn new_sel ( ) -> Sel {
438- __sel_inner ! ( "new\0 " , "new" )
469+ __sel_inner ! ( "new" , "new" )
439470}
440471
441472#[ inline]
442473pub fn dealloc_sel ( ) -> Sel {
443- __sel_inner ! ( "dealloc\0 " , "dealloc" )
474+ __sel_inner ! ( "dealloc" , "dealloc" )
444475}
445476
446477/// An undocumented selector called by the Objective-C runtime when
447478/// initializing instance variables.
448479#[ inline]
449480#[ allow( dead_code) ] // May be useful in the future
450481fn cxx_construct_sel ( ) -> Sel {
451- __sel_inner ! ( ".cxx_construct\0 " , ".cxx_construct" )
482+ __sel_inner ! ( ".cxx_construct" , ".cxx_construct" )
452483}
453484
454485/// Objective-C runtimes call `.cxx_destruct` as part of the final `dealloc`
@@ -485,7 +516,7 @@ fn cxx_construct_sel() -> Sel {
485516#[ inline]
486517#[ allow( dead_code) ] // May be useful in the future
487518fn cxx_destruct_sel ( ) -> Sel {
488- __sel_inner ! ( ".cxx_destruct\0 " , ".cxx_destruct" )
519+ __sel_inner ! ( ".cxx_destruct" , ".cxx_destruct" )
489520}
490521
491522#[ cfg( test) ]
0 commit comments