mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
528 lines
17 KiB
Swift
528 lines
17 KiB
Swift
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s
|
|
|
|
func takeClosure(_ a : () -> Int) {}
|
|
|
|
// Let decls don't get boxes for trivial types.
|
|
//
|
|
// CHECK-LABEL: sil hidden @{{.*}}test1
|
|
func test1(_ a : Int) -> Int {
|
|
// CHECK-NOT: alloc_box
|
|
// FIXME(integers): the following check should be updated for the new way +
|
|
// gets invoked. <rdar://problem/29939484>
|
|
// XCHECK-NOT: alloc_stack
|
|
|
|
let (b,c) = (a, 32)
|
|
|
|
return b+c
|
|
|
|
// CHECK: return
|
|
}
|
|
|
|
// rdar://15716277
|
|
// CHECK: @{{.*}}_destructuring
|
|
func let_destructuring() -> Int {
|
|
let (a, b) = ((1,2), 5)
|
|
return a.1+a.0+b
|
|
}
|
|
|
|
// Let decls being closed over.
|
|
//
|
|
// CHECK-LABEL: sil hidden @{{.*}}test2
|
|
func test2() {
|
|
// No allocations.
|
|
// CHECK-NOT: alloc_box
|
|
// CHECK-NOT: alloc_stack
|
|
|
|
let x = 42
|
|
|
|
takeClosure({x})
|
|
|
|
|
|
// CHECK: return
|
|
}
|
|
|
|
// The closure just returns its value, which it captured directly.
|
|
|
|
// CHECK: sil private @_T09let_decls5test2yyFSiycfU_ : $@convention(thin) (Int) -> Int
|
|
// CHECK: bb0(%0 : $Int):
|
|
// CHECK: return %0 : $Int
|
|
|
|
// Verify that we can close over let decls of tuple type.
|
|
struct RegularStruct {
|
|
var a: Int
|
|
}
|
|
func testTupleLetCapture() {
|
|
let t = (RegularStruct(a: 41), 42)
|
|
|
|
takeClosure( { t.0.a })
|
|
}
|
|
|
|
|
|
|
|
func getAString() -> String { return "" }
|
|
func useAString(_ a : String) {}
|
|
|
|
// rdar://15689514 - Verify that the cleanup for the let decl runs at the end of
|
|
// the 'let' lifetime, not at the end of the initializing expression.
|
|
//
|
|
// CHECK-LABEL: sil hidden @{{.*}}test3
|
|
func test3() {
|
|
// CHECK: [[GETFN:%[0-9]+]] = function_ref{{.*}}getAString
|
|
// CHECK-NEXT: [[STR:%[0-9]+]] = apply [[GETFN]]()
|
|
let o = getAString()
|
|
|
|
// CHECK-NOT: destroy_value
|
|
|
|
// CHECK: [[USEFN:%[0-9]+]] = function_ref{{.*}}useAString
|
|
// CHECK-NEXT: [[BORROWED_STR:%.*]] = begin_borrow [[STR]]
|
|
// CHECK-NEXT: [[STR_COPY:%.*]] = copy_value [[BORROWED_STR]]
|
|
// CHECK-NEXT: [[USE:%[0-9]+]] = apply [[USEFN]]([[STR_COPY]])
|
|
// CHECK-NEXT: end_borrow [[BORROWED_STR]] from [[STR]]
|
|
useAString(o)
|
|
|
|
// CHECK: destroy_value [[STR]]
|
|
}
|
|
// CHECK: } // end sil function '{{.*}}test3{{.*}}'
|
|
|
|
|
|
|
|
struct AddressOnlyStruct<T> {
|
|
var elt : T
|
|
var str : String
|
|
}
|
|
|
|
func produceAddressOnlyStruct<T>(_ x : T) -> AddressOnlyStruct<T> {}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructString
|
|
// CHECK: bb0([[FUNC_ARG:%.*]] : $*T):
|
|
func testAddressOnlyStructString<T>(_ a : T) -> String {
|
|
return produceAddressOnlyStruct(a).str
|
|
|
|
// CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct
|
|
// CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct<T>
|
|
// CHECK: [[ARG:%.*]] = alloc_stack $T
|
|
// CHECK: copy_addr [[FUNC_ARG]] to [initialization] [[ARG]]
|
|
// CHECK: apply [[PRODFN]]<T>([[TMPSTRUCT]], [[ARG]])
|
|
// CHECK-NEXT: dealloc_stack [[ARG]]
|
|
// CHECK-NEXT: [[STRADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct<T>, #AddressOnlyStruct.str
|
|
// CHECK-NEXT: [[STRVAL:%[0-9]+]] = load [copy] [[STRADDR]]
|
|
// CHECK-NEXT: destroy_addr [[TMPSTRUCT]]
|
|
// CHECK-NEXT: dealloc_stack [[TMPSTRUCT]]
|
|
// CHECK: return [[STRVAL]]
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyStructElt
|
|
func testAddressOnlyStructElt<T>(_ a : T) -> T {
|
|
return produceAddressOnlyStruct(a).elt
|
|
|
|
// CHECK: [[PRODFN:%[0-9]+]] = function_ref @{{.*}}produceAddressOnlyStruct
|
|
// CHECK: [[TMPSTRUCT:%[0-9]+]] = alloc_stack $AddressOnlyStruct<T>
|
|
// CHECK: [[ARG:%.*]] = alloc_stack $T
|
|
// CHECK: apply [[PRODFN]]<T>([[TMPSTRUCT]], [[ARG]])
|
|
// CHECK-NEXT: dealloc_stack [[ARG]]
|
|
// CHECK-NEXT: [[ELTADDR:%[0-9]+]] = struct_element_addr [[TMPSTRUCT]] : $*AddressOnlyStruct<T>, #AddressOnlyStruct.elt
|
|
// CHECK-NEXT: copy_addr [[ELTADDR]] to [initialization] %0 : $*T
|
|
// CHECK-NEXT: destroy_addr [[TMPSTRUCT]]
|
|
}
|
|
|
|
|
|
|
|
// rdar://15717123 - let decls of address-only type.
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyLet
|
|
func testAddressOnlyLet<T>(_ a : T) {
|
|
let x = produceAddressOnlyStruct(a)
|
|
}
|
|
|
|
|
|
func produceSubscriptableRValue() -> [String] {}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}subscriptRValue
|
|
func subscriptRValue() {
|
|
var a = produceSubscriptableRValue()[0]
|
|
}
|
|
|
|
|
|
struct GetOnlySubscriptStruct {
|
|
// get-only subscript
|
|
subscript (i : Int) -> Int { get {} }
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testGetOnlySubscript
|
|
func testGetOnlySubscript(_ x : GetOnlySubscriptStruct, idx : Int) -> Int {
|
|
return x[idx]
|
|
|
|
// CHECK: [[SUBFN:%[0-9]+]] = function_ref @{{.*}}9subscript
|
|
// CHECK-NEXT: [[CALL:%[0-9]+]] = apply [[SUBFN]](
|
|
// CHECK: return [[CALL]]
|
|
}
|
|
|
|
// Address-only let's get captured by box.
|
|
extension Optional {
|
|
func getLV() -> Int { }
|
|
}
|
|
struct CloseOverAddressOnlyConstant<T> {
|
|
func isError() {
|
|
let AOV: T?
|
|
takeClosure({ AOV.getLV() })
|
|
}
|
|
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}callThroughLet
|
|
func callThroughLet(_ predicate: @escaping (Int, Int) -> Bool) {
|
|
let p = predicate
|
|
if p(1, 2) {
|
|
}
|
|
}
|
|
|
|
|
|
// Verify that we can emit address-only rvalues directly into the result slot in
|
|
// chained calls.
|
|
struct GenericTestStruct<T> {
|
|
func pass_address_only_rvalue_result(_ i: Int) -> T {
|
|
return self[i]
|
|
}
|
|
subscript (i : Int) -> T {
|
|
get {}
|
|
set {}
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}pass_address_only_rvalue_result
|
|
// CHECK: bb0(%0 : $*T,
|
|
// CHECK: [[FN:%[0-9]+]] = function_ref @{{.*}}GenericTestStructV9subscript{{.*}}fg
|
|
// CHECK: apply [[FN]]<T>(%0,
|
|
|
|
|
|
struct NonMutableSubscriptable {
|
|
subscript(x : Int) -> Int {
|
|
get {}
|
|
nonmutating
|
|
set {}
|
|
}
|
|
}
|
|
|
|
func produceNMSubscriptableRValue() -> NonMutableSubscriptable {}
|
|
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_get
|
|
// CHECK: bb0(%0 : $Int):
|
|
// CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue
|
|
// CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]()
|
|
// CHECK: [[GETFN:%[0-9]+]] = function_ref @_T09let_decls23NonMutableSubscriptableV9subscript{{[_0-9a-zA-Z]*}}fg
|
|
// CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[GETFN]](%0, [[RES]])
|
|
// CHECK-NEXT: return [[RES2]]
|
|
func test_nm_subscript_get(_ a : Int) -> Int {
|
|
return produceNMSubscriptableRValue()[a]
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}test_nm_subscript_set
|
|
// CHECK: bb0(%0 : $Int):
|
|
// CHECK: [[FR1:%[0-9]+]] = function_ref @{{.*}}produceNMSubscriptableRValue
|
|
// CHECK-NEXT: [[RES:%[0-9]+]] = apply [[FR1]]()
|
|
// CHECK: [[SETFN:%[0-9]+]] = function_ref @_T09let_decls23NonMutableSubscriptableV9subscript{{[_0-9a-zA-Z]*}}fs
|
|
// CHECK-NEXT: [[RES2:%[0-9]+]] = apply [[SETFN]](%0, %0, [[RES]])
|
|
func test_nm_subscript_set(_ a : Int) {
|
|
produceNMSubscriptableRValue()[a] = a
|
|
}
|
|
|
|
struct WeirdPropertyTest {
|
|
// This property has a mutating getter and !mutating setter.
|
|
var p : Int {
|
|
mutating
|
|
get {}
|
|
nonmutating
|
|
set {}
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}test_weird_property
|
|
func test_weird_property(_ v : WeirdPropertyTest, i : Int) -> Int {
|
|
var v = v
|
|
// CHECK: [[VBOX:%[0-9]+]] = alloc_box ${ var WeirdPropertyTest }
|
|
// CHECK: [[PB:%.*]] = project_box [[VBOX]]
|
|
// CHECK: store %0 to [trivial] [[PB]]
|
|
|
|
// The setter isn't mutating, so we need to load the box.
|
|
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[PB]]
|
|
// CHECK: [[VVAL:%[0-9]+]] = load [trivial] [[READ]]
|
|
// CHECK: [[SETFN:%[0-9]+]] = function_ref @_T09let_decls17WeirdPropertyTestV1pSifs
|
|
// CHECK: apply [[SETFN]](%1, [[VVAL]])
|
|
v.p = i
|
|
|
|
// The getter is mutating, so it takes the box address.
|
|
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB]]
|
|
// CHECK: [[GETFN:%[0-9]+]] = function_ref @_T09let_decls17WeirdPropertyTestV1pSifg
|
|
// CHECK-NEXT: [[RES:%[0-9]+]] = apply [[GETFN]]([[WRITE]])
|
|
// CHECK: return [[RES]]
|
|
return v.p
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}generic_identity
|
|
// CHECK: bb0(%0 : $*T, %1 : $*T):
|
|
// CHECK-NEXT: debug_value_addr %1 : $*T
|
|
// CHECK-NEXT: copy_addr %1 to [initialization] %0 : $*T
|
|
// CHECK-NEXT: destroy_addr %1
|
|
// CHECK: } // end sil function '{{.*}}generic_identity{{.*}}'
|
|
func generic_identity<T>(_ a : T) -> T {
|
|
// Should be a single copy_addr, with no temporary.
|
|
return a
|
|
}
|
|
|
|
struct StaticLetMember {
|
|
static let x = 5
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testStaticLetMember
|
|
func testStaticLetMember() -> Int {
|
|
|
|
// CHECK: function_ref @{{.*}}StaticLetMemberV1xSi
|
|
// CHECK: load {{.*}} : $*Int
|
|
// CHECK-NEXT: return
|
|
return StaticLetMember.x
|
|
}
|
|
|
|
protocol SimpleProtocol {
|
|
func doSomethingGreat()
|
|
}
|
|
|
|
// Verify that no temporaries+copies are produced when calling non-@mutable
|
|
// methods on protocol and archetypes calls.
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testLetProtocolBases
|
|
// CHECK: bb0(%0 : $*SimpleProtocol):
|
|
func testLetProtocolBases(_ p : SimpleProtocol) {
|
|
// CHECK-NEXT: debug_value_addr
|
|
// CHECK-NEXT: open_existential_addr
|
|
// CHECK-NEXT: witness_method
|
|
// CHECK-NEXT: apply
|
|
p.doSomethingGreat()
|
|
|
|
// CHECK-NEXT: open_existential_addr
|
|
// CHECK-NEXT: witness_method
|
|
// CHECK-NEXT: apply
|
|
p.doSomethingGreat()
|
|
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testLetArchetypeBases
|
|
// CHECK: bb0(%0 : $*T):
|
|
func testLetArchetypeBases<T : SimpleProtocol>(_ p : T) {
|
|
// CHECK-NEXT: debug_value_addr
|
|
// CHECK-NEXT: witness_method $T
|
|
// CHECK-NEXT: apply
|
|
p.doSomethingGreat()
|
|
// CHECK-NEXT: witness_method $T
|
|
// CHECK-NEXT: apply
|
|
p.doSomethingGreat()
|
|
|
|
// CHECK-NEXT: destroy_addr %0
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testDebugValue
|
|
// CHECK: bb0(%0 : $Int, %1 : $*SimpleProtocol):
|
|
// CHECK-NEXT: debug_value %0 : $Int, let, name "a"
|
|
// CHECK-NEXT: debug_value_addr %1 : $*SimpleProtocol, let, name "b"
|
|
func testDebugValue(_ a : Int, b : SimpleProtocol) -> Int {
|
|
|
|
// CHECK-NEXT: debug_value %0 : $Int, let, name "x"
|
|
let x = a
|
|
|
|
// CHECK: apply
|
|
b.doSomethingGreat()
|
|
|
|
// CHECK: destroy_addr
|
|
|
|
// CHECK: return %0
|
|
return x
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testAddressOnlyTupleArgument
|
|
func testAddressOnlyTupleArgument(_ bounds: (start: SimpleProtocol, pastEnd: Int)) {
|
|
// CHECK: bb0(%0 : $*SimpleProtocol, %1 : $Int):
|
|
// CHECK-NEXT: %2 = alloc_stack $(start: SimpleProtocol, pastEnd: Int), let, name "bounds"
|
|
// CHECK-NEXT: %3 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 0
|
|
// CHECK-NEXT: copy_addr [take] %0 to [initialization] %3 : $*SimpleProtocol
|
|
// CHECK-NEXT: %5 = tuple_element_addr %2 : $*(start: SimpleProtocol, pastEnd: Int), 1
|
|
// CHECK-NEXT: store %1 to [trivial] %5 : $*Int
|
|
// CHECK-NEXT: debug_value_addr %2
|
|
// CHECK-NEXT: destroy_addr %2 : $*(start: SimpleProtocol, pastEnd: Int)
|
|
// CHECK-NEXT: dealloc_stack %2 : $*(start: SimpleProtocol, pastEnd: Int)
|
|
}
|
|
|
|
|
|
func address_only_let_closure<T>(_ x:T) -> T {
|
|
return { { x }() }()
|
|
}
|
|
|
|
struct GenericFunctionStruct<T, U> {
|
|
var f: (T) -> U
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}member_ref_abstraction_change
|
|
// CHECK: function_ref reabstraction thunk helper
|
|
// CHECK: return
|
|
func member_ref_abstraction_change(_ x: GenericFunctionStruct<Int, Int>) -> (Int) -> Int {
|
|
return x.f
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}call_auto_closure
|
|
// CHECK: bb0([[CLOSURE:%.*]] : $@callee_owned () -> Bool):
|
|
// CHECK: [[BORROWED_CLOSURE:%.*]] = begin_borrow [[CLOSURE]]
|
|
// CHECK: [[CLOSURE_COPY:%.*]] = copy_value [[BORROWED_CLOSURE]]
|
|
// CHECK: apply [[CLOSURE_COPY]]() : $@callee_owned () -> Bool
|
|
// CHECK: end_borrow [[BORROWED_CLOSURE]] from [[CLOSURE]]
|
|
// CHECK: destroy_value [[CLOSURE]]
|
|
// CHECK: } // end sil function '{{.*}}call_auto_closure{{.*}}'
|
|
func call_auto_closure(x: @autoclosure () -> Bool) -> Bool {
|
|
return x() // Calls of autoclosures should be marked transparent.
|
|
}
|
|
|
|
|
|
class SomeClass {}
|
|
|
|
struct AnotherStruct {
|
|
var i : Int
|
|
var c : SomeClass
|
|
}
|
|
|
|
struct StructMemberTest {
|
|
var c : SomeClass
|
|
var i = 42
|
|
var s : AnotherStruct
|
|
var t : (Int, AnotherStruct)
|
|
|
|
// rdar://15867140 - Accessing the int member here should not copy_value the
|
|
// whole struct.
|
|
func testIntMemberLoad() -> Int {
|
|
return i
|
|
}
|
|
// CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV07testIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
|
|
// CHECK: bb0([[ARG:%.*]] : $StructMemberTest):
|
|
// CHECK: debug_value [[ARG]] : $StructMemberTest, let, name "self"
|
|
// CHECK: [[TRIVIAL_VALUE:%.*]] = struct_extract [[ARG]] : $StructMemberTest, #StructMemberTest.i
|
|
// CHECK-NOT: destroy_value [[ARG]] : $StructMemberTest
|
|
// CHECK-NOT: destroy_value [[BORROWED_ARG]] : $StructMemberTest
|
|
// CHECK: return [[TRIVIAL_VALUE]] : $Int
|
|
|
|
// Accessing the int member in s should not copy_value the whole struct.
|
|
func testRecursiveIntMemberLoad() -> Int {
|
|
return s.i
|
|
}
|
|
// CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV016testRecursiveIntD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
|
|
// CHECK: bb0([[ARG:%.*]] : $StructMemberTest):
|
|
// CHECK: debug_value %0 : $StructMemberTest, let, name "self"
|
|
// CHECK: %2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.s
|
|
// CHECK: %3 = struct_extract %2 : $AnotherStruct, #AnotherStruct.i
|
|
// CHECK-NOT: destroy_value %0 : $StructMemberTest
|
|
// CHECK: return %3 : $Int
|
|
|
|
func testTupleMemberLoad() -> Int {
|
|
return t.1.i
|
|
}
|
|
// CHECK-LABEL: sil hidden @_T09let_decls16StructMemberTestV09testTupleD4LoadSiyF : $@convention(method) (@guaranteed StructMemberTest)
|
|
// CHECK: bb0(%0 : $StructMemberTest):
|
|
// CHECK-NEXT: debug_value %0 : $StructMemberTest, let, name "self"
|
|
// CHECK-NEXT: [[T0:%.*]] = struct_extract %0 : $StructMemberTest, #StructMemberTest.t
|
|
// CHECK-NEXT: [[T1:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 0
|
|
// CHECK-NEXT: [[T2:%.*]] = tuple_extract [[T0]] : $(Int, AnotherStruct), 1
|
|
// CHECK-NEXT: [[T3:%.*]] = struct_extract [[T2]] : $AnotherStruct, #AnotherStruct.i
|
|
// CHECK-NEXT: return [[T3]] : $Int
|
|
|
|
}
|
|
|
|
struct GenericStruct<T> {
|
|
var a : T
|
|
var b : Int
|
|
|
|
func getA() -> T {
|
|
return a
|
|
}
|
|
// CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getA{{.*}} : $@convention(method) <T> (@in_guaranteed GenericStruct<T>) -> @out T
|
|
// CHECK: bb0(%0 : $*T, %1 : $*GenericStruct<T>):
|
|
// CHECK-NEXT: debug_value_addr %1 : $*GenericStruct<T>, let, name "self"
|
|
// CHECK-NEXT: %3 = struct_element_addr %1 : $*GenericStruct<T>, #GenericStruct.a
|
|
// CHECK-NEXT: copy_addr %3 to [initialization] %0 : $*T
|
|
// CHECK-NEXT: %5 = tuple ()
|
|
// CHECK-NEXT: return %5 : $()
|
|
|
|
func getB() -> Int {
|
|
return b
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}GenericStructV4getB{{.*}} : $@convention(method) <T> (@in_guaranteed GenericStruct<T>) -> Int
|
|
// CHECK: bb0([[SELF_ADDR:%.*]] : $*GenericStruct<T>):
|
|
// CHECK-NEXT: debug_value_addr [[SELF_ADDR]] : $*GenericStruct<T>, let, name "self"
|
|
// CHECK-NEXT: [[PROJ_ADDR:%.*]] = struct_element_addr [[SELF_ADDR]] : $*GenericStruct<T>, #GenericStruct.b
|
|
// CHECK-NEXT: [[PROJ_VAL:%.*]] = load [trivial] [[PROJ_ADDR]] : $*Int
|
|
// CHECK-NOT: destroy_addr [[SELF]] : $*GenericStruct<T>
|
|
// CHECK-NEXT: return [[PROJ_VAL]] : $Int
|
|
}
|
|
|
|
|
|
// rdar://15877337
|
|
struct LetPropertyStruct {
|
|
let lp : Int
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @{{.*}}testLetPropertyAccessOnLValueBase
|
|
// CHECK: bb0(%0 : $LetPropertyStruct):
|
|
// CHECK: [[ABOX:%[0-9]+]] = alloc_box ${ var LetPropertyStruct }
|
|
// CHECK: [[A:%[0-9]+]] = project_box [[ABOX]]
|
|
// CHECK: store %0 to [trivial] [[A]] : $*LetPropertyStruct
|
|
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] [[A]]
|
|
// CHECK: [[STRUCT:%[0-9]+]] = load [trivial] [[READ]] : $*LetPropertyStruct
|
|
// CHECK: [[PROP:%[0-9]+]] = struct_extract [[STRUCT]] : $LetPropertyStruct, #LetPropertyStruct.lp
|
|
// CHECK: destroy_value [[ABOX]] : ${ var LetPropertyStruct }
|
|
// CHECK: return [[PROP]] : $Int
|
|
func testLetPropertyAccessOnLValueBase(_ a : LetPropertyStruct) -> Int {
|
|
var a = a
|
|
return a.lp
|
|
}
|
|
|
|
|
|
var addressOnlyGetOnlyGlobalProperty : SimpleProtocol { get {} }
|
|
|
|
// CHECK-LABEL: sil hidden @_T09let_decls018testAddressOnlyGetE14GlobalPropertyAA14SimpleProtocol_pyF
|
|
// CHECK: bb0(%0 : $*SimpleProtocol):
|
|
// CHECK-NEXT: // function_ref
|
|
// CHECK-NEXT: %1 = function_ref @_T09let_decls014addressOnlyGetD14GlobalPropertyAA14SimpleProtocol_pfg
|
|
// CHECK-NEXT: %2 = apply %1(%0) : $@convention(thin) () -> @out SimpleProtocol
|
|
// CHECK-NEXT: %3 = tuple ()
|
|
// CHECK-NEXT: return %3 : $()
|
|
// CHECK-NEXT: }
|
|
func testAddressOnlyGetOnlyGlobalProperty() -> SimpleProtocol {
|
|
return addressOnlyGetOnlyGlobalProperty
|
|
}
|
|
|
|
|
|
// rdar://15962740
|
|
struct LetDeclInStruct {
|
|
let immutable: Int
|
|
init() {
|
|
immutable = 1
|
|
}
|
|
}
|
|
|
|
// rdar://19854166 - Swift 1.2 uninitialized constant causes crash
|
|
// The destroy_addr for a let stack temporary should be generated against
|
|
// mark_uninitialized instruction, so DI will see it.
|
|
func test_unassigned_let_constant() {
|
|
let string : String
|
|
}
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $String, let, name "string"
|
|
// CHECK-NEXT: [[MUI:%[0-9]+]] = mark_uninitialized [var] [[S]] : $*String
|
|
// CHECK-NEXT: destroy_addr [[MUI]] : $*String
|
|
// CHECK-NEXT: dealloc_stack [[S]] : $*String
|
|
|