@@ -118,3 +118,95 @@ public func testWithMemoryRebound<T, Result>(
118118 }
119119 return try body(.init(rawPtr))
120120}
121+
122+ @_silgen_name( " takeRawPointer" )
123+ func takeRawPointer( _: UnsafeRawPointer)
124+
125+ @_silgen_name ( " takeObjectPointer " )
126+ func takeObjectPointer( _: UnsafePointer < AnyObject > )
127+
128+ @_silgen_name( " takeStringPointer" )
129+ func takeStringPointer( _: UnsafePointer < String > )
130+
131+ @_silgen_name( " takeDictionaryPointer" )
132+ func takeDictionaryPointer( _: UnsafePointer < Dictionary < Int , Int > > )
133+
134+ // Test conversion of a dictionary to a raw pointer. This is not a sane
135+ // conversion, but the compiler must still generate memory-safe code.
136+ //
137+ // A dictionary is an eager-move type, so it will be destroyed at its
138+ // last use. An address_to_pointer operation escapes the pointer, so
139+ // the compiler never sees those pointer uses. The pointer's scope
140+ // must be protected by a fix_lifetime.
141+ //
142+ // NOTE: If this test triggers a compiler error because of the unsafe
143+ // inout conversion, then we have arrived at a better world. Delete
144+ // the test. The eagerMoveToPointer test below is sufficient.
145+ //
146+ // CHECK-LABEL: sil [stack_protection] @$s18pointer_conversion22dictionaryToRawPointeryyF : $@convention(thin) () -> () {
147+ // CHECK: [[A:%.*]] = alloc_stack $Dictionary<Int, Int>, var, name "d"
148+ // CHECK: [[PTR:%.*]] = address_to_pointer [stack_protection] [[A]] : $*Dictionary<Int, Int> to $Builtin.RawPointer
149+ // CHECK: [[UP:%.*]] = struct $UnsafeRawPointer ([[PTR]] : $Builtin.RawPointer)
150+ // CHECK: apply %{{.*}}([[UP]]) : $@convention(thin) (UnsafeRawPointer) -> ()
151+ // CHECK: [[D:%.*]] = load %0 : $*Dictionary<Int, Int>
152+ // CHECK: fix_lifetime [[D]] : $Dictionary<Int, Int>
153+ // CHECK: release_value [[D]] : $Dictionary<Int, Int>
154+ // CHECK: dealloc_stack [[A]] : $*Dictionary<Int, Int>
155+ // CHECK-LABEL: } // end sil function '$s18pointer_conversion22dictionaryToRawPointeryyF'
156+ public func dictionaryToRawPointer( ) {
157+ var d = [ 1 : 1 ]
158+ takeRawPointer ( & d)
159+ }
160+
161+ // Test conversion of a non-trivial eager-move type to a raw pointer.
162+ // This currently only applies to Dictionary, but converting a
163+ // dictionary to a pointer will likely be a compiler error in the
164+ // future. So force an eagerMove type here.
165+ //
166+ // An eager-move type will be destroyed at its last use. An
167+ // address_to_pointer operation escapes the pointer, so the compiler
168+ // never sees those pointer uses. The pointer's scope must be
169+ // protected by a fix_lifetime.
170+ // CHECK-LABEL: sil [stack_protection] @$s18pointer_conversion18eagerMoveToPointer1oyyXln_tF : $@convention(thin) (@owned AnyObject) -> () {
171+ // CHECK: [[A:%.*]] = alloc_stack [moveable_value_debuginfo] $AnyObject, var, name "o"
172+ // CHECK: [[PTR:%.*]] = address_to_pointer [stack_protection] [[A]] : $*AnyObject to $Builtin.RawPointer
173+ // CHECK: [[UP:%.*]] = struct $UnsafePointer<AnyObject> ([[PTR]] : $Builtin.RawPointer)
174+ // CHECK: apply %{{.*}}([[UP]]) : $@convention(thin) (UnsafePointer<AnyObject>) -> ()
175+ // CHECK: [[O:%.*]] = load [[A]] : $*AnyObject
176+ // CHECK: fix_lifetime [[O]] : $AnyObject
177+ // CHECK: strong_release [[O]] : $AnyObject
178+ // CHECK: dealloc_stack [[A]] : $*AnyObject
179+ // CHECK-LABEL: } // end sil function '$s18pointer_conversion18eagerMoveToPointer1oyyXln_tF'
180+ public func eagerMoveToPointer( @_eagerMove o: consuming AnyObject ) {
181+ takeObjectPointer ( & o)
182+ }
183+
184+ // CHECK-LABEL: sil [stack_protection] @$s18pointer_conversion15stringToPointer2ssySS_tF : $@convention(thin) (@guaranteed String) -> () {
185+ // CHECK: [[A:%.*]] = alloc_stack $String, var, name "s"
186+ // CHECK: [[PTR:%.*]] = address_to_pointer [stack_protection] [[A]] : $*String to $Builtin.RawPointer
187+ // CHECK: [[UP:%.*]] = struct $UnsafePointer<String> ([[PTR]] : $Builtin.RawPointer)
188+ // CHECK: apply {{.*}}([[UP]]) : $@convention(thin) (UnsafePointer<String>) -> ()
189+ // CHECK: [[S:%.*]] = load [[A]] : $*String
190+ // CHECK: fix_lifetime [[S]] : $String
191+ // CHECK: release_value [[S]] : $String
192+ // CHECK: dealloc_stack [[A]] : $*String
193+ // CHECK-LABEL: } // end sil function '$s18pointer_conversion15stringToPointer2ssySS_tF'
194+ public func stringToPointer( ss: String ) {
195+ var s = ss
196+ takeStringPointer ( & s)
197+ }
198+
199+ // CHECK-LABEL: sil [stack_protection] @$s18pointer_conversion19dictionaryToPointer2ddySDyS2iG_tF : $@convention(thin) (@guaranteed Dictionary<Int, Int>) -> () {
200+ // CHECK: [[A:%.*]] = alloc_stack $Dictionary<Int, Int>, var, name "d"
201+ // CHECK: [[PTR:%.*]] = address_to_pointer [stack_protection] [[A]] : $*Dictionary<Int, Int> to $Builtin.RawPointer
202+ // CHECK: [[UP:%.*]] = struct $UnsafePointer<Dictionary<Int, Int>> ([[PTR]] : $Builtin.RawPointer)
203+ // CHECK: apply %{{.*}}([[UP]]) : $@convention(thin) (UnsafePointer<Dictionary<Int, Int>>) -> ()
204+ // CHECK: [[D:%.*]] = load [[A]] : $*Dictionary<Int, Int>
205+ // CHECK: fix_lifetime [[D]] : $Dictionary<Int, Int>
206+ // CHECK: release_value [[D]] : $Dictionary<Int, Int>
207+ // CHECK: dealloc_stack [[A]] : $*Dictionary<Int, Int>
208+ // CHECK-LABEL: } // end sil function '$s18pointer_conversion19dictionaryToPointer2ddySDyS2iG_tF'
209+ public func dictionaryToPointer( dd: Dictionary < Int , Int > ) {
210+ var d = dd
211+ takeDictionaryPointer ( & d)
212+ }
0 commit comments