@@ -81,73 +81,144 @@ impl Drop for AutoreleasePool {
8181    } 
8282} 
8383
84- // TODO: 
85- // #![feature(negative_impls)] 
86- // #![feature(auto_traits)] 
87- // /// A trait for the sole purpose of ensuring we can't pass an `&AutoreleasePool` 
88- // /// through to the closure inside `autoreleasepool` 
89- // pub unsafe auto trait AutoreleaseSafe {} 
90- // // TODO: Unsure how negative impls work exactly 
91- // unsafe impl !AutoreleaseSafe for AutoreleasePool {} 
92- // unsafe impl !AutoreleaseSafe for &AutoreleasePool {} 
93- // unsafe impl !AutoreleaseSafe for &mut AutoreleasePool {} 
84+ /// A trait for the sole purpose of ensuring we can't pass an `&AutoreleasePool` 
85+ /// through to the closure inside `autoreleasepool` 
86+ #[ cfg( feature = "unstable_autoreleasesafe" ) ]  
87+ pub  unsafe  auto trait  AutoreleaseSafe  { } 
88+ // TODO: Unsure how negative impls work exactly 
89+ #[ cfg( feature = "unstable_autoreleasesafe" ) ]  
90+ impl  !AutoreleaseSafe  for  AutoreleasePool  { } 
9491
95- /// Execute `f` in the context of a new autorelease pool. The pool is drained 
96- /// after the execution of `f` completes. 
97- /// 
98- /// This corresponds to `@autoreleasepool` blocks in Objective-C and Swift. 
99- /// 
100- /// The pool is passed as a reference to the enclosing function to give it a 
101- /// lifetime parameter that autoreleased objects can refer to. 
102- /// 
103- /// # Examples 
104- /// 
105- /// ```rust 
106- /// use objc::{class, msg_send}; 
107- /// use objc::rc::{autoreleasepool, AutoreleasePool}; 
108- /// use objc::runtime::Object; 
109- /// 
110- /// fn needs_lifetime_from_pool<'p>(_pool: &'p AutoreleasePool) -> &'p mut Object { 
111- ///     let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; 
112- ///     let obj: *mut Object = unsafe { msg_send![obj, autorelease] }; 
113- ///     // SAFETY: Lifetime bounded by the pool 
114- ///     unsafe { &mut *obj } 
115- /// } 
116- /// 
117- /// autoreleasepool(|pool| { 
118- ///     let obj = needs_lifetime_from_pool(pool); 
119- ///     // Use `obj` 
120- /// }); 
121- /// 
122- /// // `obj` is deallocated when the pool ends 
123- /// ``` 
124- /// 
125- /// ```rust,compile_fail 
126- /// # use objc::{class, msg_send}; 
127- /// # use objc::rc::{autoreleasepool, AutoreleasePool}; 
128- /// # use objc::runtime::Object; 
129- /// # 
130- /// # fn needs_lifetime_from_pool<'p>(_pool: &'p AutoreleasePool) -> &'p mut Object { 
131- /// #     let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; 
132- /// #     let obj: *mut Object = unsafe { msg_send![obj, autorelease] }; 
133- /// #     unsafe { &mut *obj } 
134- /// # } 
135- /// # 
136- /// // Fails to compile because `obj` does not live long enough for us to 
137- /// // safely take it out of the pool. 
138- /// 
139- /// let obj = autoreleasepool(|pool| { 
140- ///     let obj = needs_lifetime_from_pool(pool); 
141- ///     // Use `obj` 
142- ///     obj 
143- /// }); 
144- /// ``` 
145- /// 
146- /// TODO: More examples. 
147- pub  fn  autoreleasepool < T ,  F > ( f :  F )  -> T 
148- where 
149-     for < ' p >  F :  FnOnce ( & ' p  AutoreleasePool )  -> T ,  // + AutoreleaseSafe, 
150- { 
151-     let  pool = unsafe  {  AutoreleasePool :: new ( )  } ; 
152-     f ( & pool) 
92+ #[ cfg( feature = "unstable_autoreleasesafe" ) ]  
93+ macro_rules!  fn_autoreleasepool { 
94+     { $( #[ $fn_meta: meta] ) *  $v: vis fn  $fn: ident( $f: ident)  $b: block}  => { 
95+         $( #[ $fn_meta] ) * 
96+         $v fn  $fn<T ,  F >( $f:  F )  -> T 
97+         where 
98+             for <' p> F :  FnOnce ( & ' p AutoreleasePool )  -> T  + AutoreleaseSafe , 
99+         { 
100+             $b
101+         } 
102+     } 
103+ } 
104+ 
105+ #[ cfg( not( feature = "unstable_autoreleasesafe" ) ) ]  
106+ macro_rules!  fn_autoreleasepool { 
107+     { $( #[ $fn_meta: meta] ) *  $v: vis fn  $fn: ident( $f: ident)  $b: block}  => { 
108+         $( #[ $fn_meta] ) * 
109+         $v fn  $fn<T ,  F >( $f:  F )  -> T 
110+         where 
111+             for <' p> F :  FnOnce ( & ' p AutoreleasePool )  -> T , 
112+         { 
113+             $b
114+         } 
115+     } 
116+ } 
117+ 
118+ fn_autoreleasepool ! ( 
119+     /// Execute `f` in the context of a new autorelease pool. The pool is 
120+      /// drained after the execution of `f` completes. 
121+      /// 
122+      /// This corresponds to `@autoreleasepool` blocks in Objective-C and 
123+      /// Swift. 
124+      /// 
125+      /// The pool is passed as a reference to the enclosing function to give it 
126+      /// a lifetime parameter that autoreleased objects can refer to. 
127+      /// 
128+      /// The given reference must not be used in an inner `autoreleasepool`, 
129+      /// doing so will be a compile error in a future release. You can test 
130+      /// this guarantee with the `unstable_autoreleasesafe` crate feature on 
131+      /// nightly Rust. 
132+      /// 
133+      /// So using `autoreleasepool` is unsound right now because of this 
134+      /// specific problem. 
135+      /// 
136+      /// # Examples 
137+      /// 
138+      /// Basic usage: 
139+      /// 
140+      /// ```rust 
141+      /// use objc::{class, msg_send}; 
142+      /// use objc::rc::{autoreleasepool, AutoreleasePool}; 
143+      /// use objc::runtime::Object; 
144+      /// 
145+      /// fn needs_lifetime_from_pool<'p>(_pool: &'p AutoreleasePool) -> &'p mut Object { 
146+      ///     let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; 
147+      ///     let obj: *mut Object = unsafe { msg_send![obj, autorelease] }; 
148+      ///     // SAFETY: Lifetime bounded by the pool 
149+      ///     unsafe { &mut *obj } 
150+      /// } 
151+      /// 
152+      /// autoreleasepool(|pool| { 
153+      ///     // Create `obj` and autorelease it to the pool 
154+      ///     let obj = needs_lifetime_from_pool(pool); 
155+      ///     // ... use `obj` here 
156+      ///     // `obj` is deallocated when the pool ends 
157+      /// }); 
158+      /// ``` 
159+      /// 
160+      /// Fails to compile because `obj` does not live long enough for us to 
161+      /// safely take it out of the pool: 
162+      /// 
163+      /// ```rust,compile_fail 
164+      /// # use objc::{class, msg_send}; 
165+      /// # use objc::rc::{autoreleasepool, AutoreleasePool}; 
166+      /// # use objc::runtime::Object; 
167+      /// # 
168+      /// # fn needs_lifetime_from_pool<'p>(_pool: &'p AutoreleasePool) -> &'p mut Object { 
169+      /// #     let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; 
170+      /// #     let obj: *mut Object = unsafe { msg_send![obj, autorelease] }; 
171+      /// #     unsafe { &mut *obj } 
172+      /// # } 
173+      /// # 
174+      /// let obj = autoreleasepool(|pool| { 
175+      ///     let obj = needs_lifetime_from_pool(pool); 
176+      ///     // Use `obj` 
177+      ///     obj 
178+      /// }); 
179+      /// ``` 
180+      /// 
181+      /// Incorrect usage which causes undefined behaviour: 
182+      /// 
183+      #[ cfg_attr( feature = "unstable_autoreleasesafe" ,  doc = "```rust,compile_fail" ) ] 
184+     #[ cfg_attr( not( feature = "unstable_autoreleasesafe" ) ,  doc = "```rust" ) ] 
185+     /// # use objc::{class, msg_send}; 
186+      /// # use objc::rc::{autoreleasepool, AutoreleasePool}; 
187+      /// # use objc::runtime::Object; 
188+      /// # 
189+      /// # fn needs_lifetime_from_pool<'p>(_pool: &'p AutoreleasePool) -> &'p mut Object { 
190+      /// #     let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] }; 
191+      /// #     let obj: *mut Object = unsafe { msg_send![obj, autorelease] }; 
192+      /// #     unsafe { &mut *obj } 
193+      /// # } 
194+      /// # 
195+      /// autoreleasepool(|outer_pool| { 
196+      ///     let obj = autoreleasepool(|inner_pool| { 
197+      ///         let obj = needs_lifetime_from_pool(outer_pool); 
198+      ///         obj 
199+      ///     }); 
200+      ///     // `obj` can wrongly be used here because it's lifetime was 
201+      ///     // assigned to the outer pool, even though it was released by the 
202+      ///     // inner pool already. 
203+      /// }); 
204+      /// ``` 
205+      pub  fn  autoreleasepool( f)  { 
206+         let  pool = unsafe  {  AutoreleasePool :: new( )  } ; 
207+         f( & pool) 
208+     } 
209+ ) ; 
210+ 
211+ #[ cfg( all( test,  feature = "unstable_autoreleasesafe" ) ) ]  
212+ mod  tests { 
213+     use  super :: AutoreleaseSafe ; 
214+     use  crate :: runtime:: Object ; 
215+ 
216+     fn  requires_autoreleasesafe < T :  AutoreleaseSafe > ( )  { } 
217+ 
218+     #[ test]  
219+     fn  test_autoreleasesafe ( )  { 
220+         requires_autoreleasesafe :: < usize > ( ) ; 
221+         requires_autoreleasesafe :: < * mut  Object > ( ) ; 
222+         requires_autoreleasesafe :: < & mut  Object > ( ) ; 
223+     } 
153224} 
0 commit comments