mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
141 lines
5.7 KiB
Swift
141 lines
5.7 KiB
Swift
// RUN: %target-swift-frontend -enforce-exclusivity=checked -Onone -Xllvm -sil-print-types -emit-sil -parse-as-library %s -Xllvm -debug-only=access-enforcement-selection 2>&1 | %FileCheck %s
|
|
// REQUIRES: asserts
|
|
|
|
// This is a source-level test because it helps bring up the entire -Onone pipeline with the access markers.
|
|
|
|
public func takesInout(_ i: inout Int) {
|
|
i = 42
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection10takesInoutyySizF
|
|
// CHECK: Static Access: %{{.*}} = begin_access [modify] [static] %{{.*}} : $*Int
|
|
|
|
// Helper taking a basic, no-escape closure.
|
|
func takeClosure(_: ()->Int) {}
|
|
|
|
// Helper taking an escaping closure.
|
|
func takeClosureAndInout(_: inout Int, _: @escaping ()->Int) {}
|
|
|
|
// Helper taking an escaping closure.
|
|
func takeEscapingClosure(_: @escaping ()->Int) {}
|
|
|
|
// Generate an alloc_stack that escapes into a closure.
|
|
public func captureStack() -> Int {
|
|
// Use a `var` so `x` isn't treated as a literal.
|
|
var x = 3
|
|
takeClosure { return x }
|
|
return x
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection12captureStackSiyF
|
|
// Dynamic access for `return x`. Since the closure is non-escaping, using
|
|
// dynamic enforcement here is more conservative than it needs to be -- static
|
|
// is sufficient here.
|
|
// CHECK: Static Access: %{{.*}} = begin_access [read] [static] %{{.*}} : $*Int
|
|
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection12captureStackSiyFSiyXEfU_
|
|
// CHECK: Static Access: %{{.*}} = begin_access [read] [static] %{{.*}} : $*Int
|
|
|
|
|
|
// Generate an alloc_stack that does not escape into a closure.
|
|
public func nocaptureStack() -> Int {
|
|
var x = 3
|
|
takeClosure { return 5 }
|
|
return x
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection14nocaptureStackSiyF
|
|
// Static access for `return x`.
|
|
// CHECK: Static Access: %{{.*}} = begin_access [read] [static] %{{.*}} : $*Int
|
|
//
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection14nocaptureStackSiyFSiyXEfU_
|
|
|
|
// Generate an alloc_stack that escapes into a closure while an access is
|
|
// in progress.
|
|
public func captureStackWithInoutInProgress() -> Int {
|
|
// Use a `var` so `x` isn't treated as a literal.
|
|
var x = 3
|
|
takeClosureAndInout(&x) { return x }
|
|
return x
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection31captureStackWithInoutInProgressSiyF
|
|
// Access for `return x`.
|
|
// CHECK-DAG: Dynamic Access: %{{.*}} = begin_access [read] [dynamic] %{{.*}} : $*Int
|
|
// Access for `&x`.
|
|
// CHECK-DAG: Dynamic Access: %{{.*}} = begin_access [modify] [dynamic] %{{.*}} : $*Int
|
|
//
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection31captureStackWithInoutInProgressSiyF
|
|
// CHECK: Dynamic Access: %{{.*}} = begin_access [read] [dynamic] %{{.*}} : $*Int
|
|
|
|
// Generate an alloc_box that escapes into a closure.
|
|
// FIXME: `x` is eventually promoted to an alloc_stack even though it has dynamic enforcement.
|
|
// We should ensure that alloc_stack variables are statically enforced.
|
|
public func captureBox() -> Int {
|
|
var x = 3
|
|
takeEscapingClosure { x = 4; return x }
|
|
return x
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection10captureBoxSiyF
|
|
// Dynamic access for `return x`.
|
|
// CHECK: Dynamic Access: %{{.*}} = begin_access [read] [dynamic] %{{.*}} : $*Int
|
|
// CHECK-LABEL: $s28access_enforcement_selection10captureBoxSiyFSiycfU_
|
|
|
|
// Generate a closure in which the @inout_aliasing argument
|
|
// escapes to an @inout function `bar`.
|
|
public func recaptureStack() -> Int {
|
|
var x = 3
|
|
takeClosure { takesInout(&x); return x }
|
|
return x
|
|
}
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection14recaptureStackSiyF
|
|
//
|
|
// Static access for `return x`.
|
|
// CHECK: Static Access: %{{.*}} = begin_access [read] [static] %{{.*}} : $*Int
|
|
|
|
// CHECK-LABEL: Access Enforcement Selection in $s28access_enforcement_selection14recaptureStackSiyFSiyXEfU_
|
|
//
|
|
// The first [modify] access inside the closure is static. It enforces the
|
|
// @inout argument.
|
|
// CHECK: Static Access: %{{.*}} = begin_access [modify] [static] %{{.*}} : $*Int
|
|
//
|
|
// The second [read] access is static. Same as `captureStack` above.
|
|
//
|
|
// CHECK: Static Access: %{{.*}} = begin_access [read] [static] %{{.*}} : $*Int
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Inout access in a recursive non-escaping closure currently has
|
|
// static enforcement.
|
|
|
|
public protocol Apply {
|
|
func apply(_ body: (Apply) -> ())
|
|
}
|
|
|
|
// CHECK-LABEL: sil private @$s28access_enforcement_selection20testRecursiveClosure1a1xyAA5Apply_p_SiztF9localFuncL_1byAaE_p_tF : $@convention(thin) (@in_guaranteed any Apply, @inout_aliasable Int) -> () {
|
|
// CHECK: bb0(%0 : $*any Apply, %1 : @closureCapture $*Int):
|
|
// CHECK: begin_access [modify] [static] %1 : $*Int
|
|
// CHECK-LABEL: } // end sil function '$s28access_enforcement_selection20testRecursiveClosure1a1xyAA5Apply_p_SiztF9localFuncL_1byAaE_p_tF'
|
|
public func testRecursiveClosure(a: Apply, x: inout Int) {
|
|
func localFunc(b: Apply) {
|
|
x += 1
|
|
let closure = { (c: Apply) in
|
|
c.apply(localFunc)
|
|
}
|
|
b.apply(closure)
|
|
}
|
|
a.apply(localFunc)
|
|
}
|
|
|
|
// CHECK-LABEL: sil private @$s28access_enforcement_selection25testRecursiveLocalCapture1iys5Int64Vz_tF6local2L_yyF : $@convention(thin) (@inout_aliasable Int64) -> () {
|
|
// CHECK: begin_access [modify] [static] %0 : $*Int64
|
|
// CHECK-LABEL: } // end sil function '$s28access_enforcement_selection25testRecursiveLocalCapture1iys5Int64Vz_tF6local2L_yyF'
|
|
func testRecursiveLocalCapture(i: inout Int64) {
|
|
func local1() {
|
|
if i < 1 {
|
|
local2()
|
|
}
|
|
}
|
|
func local2() {
|
|
i = i + 1
|
|
local1()
|
|
}
|
|
local1()
|
|
}
|