// RUN: %target-swift-frontend -parse-as-library -disable-availability-checking -enable-experimental-feature RawLayout -import-objc-header %S/Inputs/perf-annotations.h -emit-sil %s -o /dev/null -verify // REQUIRES: swift_in_compiler // REQUIRES: optimized_stdlib // REQUIRES: swift_feature_RawLayout protocol P { func protoMethod(_ a: Int) -> Int } open class Cl { open func classMethod() {} final func finalMethod() {} } func initFunc() -> Int { return Int.random(in: 0..<10) } struct Str : P { let x: Int func protoMethod(_ a: Int) -> Int { return a + x } static let s = 27 << 0 static var s2 = 10 + s static var s3 = initFunc() // expected-error {{global/static variable initialization can cause locking}} } struct AllocatingStr : P { func protoMethod(_ a: Int) -> Int { _ = Cl() // expected-error {{Using type 'Cl' can cause metadata allocation or locks}} return 0 } } func noRTCallsForArrayGet(_ a: [Str], _ i: Int) -> Int { return a[i].x } @_noLocks func callArrayGet(_ a: [Str]) -> Int { return noRTCallsForArrayGet(a, 0) } @_noLocks func arcOperations(_ x: Cl) -> Cl { return x // expected-error {{this code performs reference counting operations which can cause locking}} } func genFunc(_ t: T, _ a: Int) -> Int { let s = t return t.protoMethod(a) + s.protoMethod(a) // expected-note {{called from here}} } @_noAllocation func callMethodGood(_ a: Int) -> Int { return genFunc(Str(x: 1), a) } @_noAllocation func callMethodBad(_ a: Int) -> Int { return genFunc(AllocatingStr(), a) // expected-note {{called from here}} } @_noAllocation func callClassMethod(_ c: Cl) { return c.classMethod() // expected-error {{called function is not known at compile time and can have unpredictable performance}} } @_noAllocation func callFinalMethod(_ c: Cl) { return c.finalMethod() } @_noAllocation func callProtocolMethod(_ p: P) -> Int { return p.protoMethod(0) // expected-error {{this code pattern can cause metadata allocation or locks}} } @_noAllocation func dynamicCast(_ a: AnyObject) -> Cl? { return a as? Cl // expected-error {{dynamic casting can lock or allocate}} } @_noAllocation func testUnsafePerformance(_ idx: Int) -> [Int] { return _unsafePerformance { [10, 20, 30, 40] } } @_noAllocation func testMemoryLayout() -> Int { return MemoryLayout.size + MemoryLayout.stride + MemoryLayout.alignment } class MyError : Error {} class MyError2 : Error {} @_noLocks func errorExistential(_ b: Bool) throws -> Int { if b { return 28 } throw MyError() // expected-error{{Using type 'MyError' can cause metadata allocation or locks}} } @_noLocks func concreteThrowsExistential(_ b: Bool) throws -> Int { if b { return 28 } throw ErrorEnum.tryAgain // expected-error{{Using type 'any Error' can cause metadata allocation or locks}} } @_noLocks func multipleThrows(_ b1: Bool, _ b2: Bool) throws -> Int { if b1 { throw MyError() // expected-error{{Using type 'MyError' can cause metadata allocation or locks}} } if b2 { throw MyError2() } return 28 } @_noLocks func testCatch(_ b: Bool) throws -> Int? { do { return try errorExistential(true) } catch let e as MyError { // expected-error{{this code performs reference counting operations which can cause locking}} print(e) return nil } } enum ErrorEnum: Error { case failed case tryAgain } @_noLocks func concreteError(_ b: Bool) throws(ErrorEnum) -> Int { if b { return 28 } throw .tryAgain } func concreteErrorOther(_ b: Bool) throws(ErrorEnum) -> Int { if b { return 28 } throw .tryAgain } @_noLocks func testCatchConcrete(_ b: Bool) -> Int { do { return try concreteError(b) + concreteErrorOther(b) } catch { return 17 } } @_noLocks func testRecursion(_ i: Int) -> Int { if i > 0 { return testRecursion(i - 1) } return 0 } @_noLocks func testGlobal() -> Int { return Str.s + Str.s2 } @_noLocks func testGlobalWithComplexInit() -> Int { return Str.s3 // expected-note {{called from here}} } func metatypeArg(_ t: T.Type, _ b: Bool) { } @_noAllocation func callFuncWithMetatypeArg() { metatypeArg(Int.self, false) } @_noAllocation func intConversion() { let x = 42 _ = UInt(x) } @_noAllocation func integerRange() { for _ in 0 ..< 10 { } } struct GenStruct { var a: A } @_noAllocation func memoryLayout() -> Int? { return MemoryLayout>.size } class H { var hash: Int { 27 } } struct MyStruct { static var v: Int = { // expected-error {{Using type 'H' can cause metadata allocation or locks}} return H().hash }() } @_noAllocation func globalWithInitializer(x: MyStruct) { _ = MyStruct.v // expected-note {{called from here}} } @_noAllocation func callBadClosure(closure: ()->Int) -> Int { return closure() } @_noAllocation func badClosure() { _ = callBadClosure(closure: { // expected-note {{called from here}} _ = Cl() // expected-error {{Using type 'Cl' can cause metadata allocation or locks}} return 42 }) } func badClosure2() { _ = callBadClosure(closure: { // expected-note {{called from here}} _ = Cl() // expected-error {{Using type 'Cl' can cause metadata allocation or locks}} return 42 }) } @_noAllocation func callGoodClosure(closure: ()->Int) -> Int { return closure() } @_noAllocation func goodClosure() { _ = callBadClosure(closure: { return 42 }) } func goodClosure2() { _ = callBadClosure(closure: { return 42 }) } @_noAllocation func closueWhichModifiesLocalVar() -> Int { var x = 42 let localNonEscapingClosure = { x += 1 } localNonEscapingClosure() return x } struct Buffer { var p: UnsafeMutableRawBufferPointer func bind(of type: T.Type) -> UnsafeMutableBufferPointer { self.p.bindMemory(to: T.self) } @_noAllocation func callBind() -> UnsafeMutableBufferPointer { return bind(of: Int.self) } } @_noLocks func testBitShift(_ x: Int) -> Int { return x << 1 } @_noLocks func testUintIntConversion() -> Int { let u: UInt32 = 5 return Int(u) } struct OptSet: OptionSet { let rawValue: Int public static var a: OptSet { return OptSet(rawValue: 1) } public static var b: OptSet { return OptSet(rawValue: 2) } public static var c: OptSet { return OptSet(rawValue: 4) } public static var d: OptSet { return OptSet(rawValue: 8) } } @_noLocks func testOptionSet(_ options: OptSet) -> Bool { return options.contains(.b) } let globalA = 0xff let globalB = UInt32(globalA) @_noLocks func testGlobalsWithConversion() -> UInt32 { return globalB } public struct X: Collection { public func index(after i: Int) -> Int { return i + 1 } public subscript(position: Int) -> Int { get { return 0 } } public var startIndex: Int = 0 public var endIndex: Int = 1 public typealias Index = Int } extension Collection where Element: Comparable { public func testSorted() -> Int { return testSorted(by: <) } public func testSorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> Int { let x = 0 _ = areInIncreasingOrder(self.first!, self.first!) return x } } @_noLocks public func testCollectionSort(a: X) -> Int { _ = a.testSorted() return 0 } public struct Y { var a, b, c: Int } extension Y { func with2(_ body: () -> ()) { body() } func with1(_ body: (Int) -> (Int)) -> Int { with2 { _ = body(48) } return 777 } func Xsort() -> Int { with1 { i in i } } } @_noLocks public func testClosurePassing(a: inout Y) -> Int { return a.Xsort() } struct LargeGenericStruct { var a: T var b: T var c: T var d: T var e: T var f: T var g: T var h: T } var largeGeneric = LargeGenericStruct(a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8) @_noLocks func testLargeGenericStruct() -> LargeGenericStruct { return largeGeneric } struct ContainsLargeGenericStruct { var s: LargeGenericStruct } var clgs = ContainsLargeGenericStruct(s: LargeGenericStruct(a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8)) @_noLocks func testClgs() -> ContainsLargeGenericStruct { return clgs } struct NestedGenericStruct { var a: T var b: T var c: LargeGenericStruct var d: T var e: T var f: T var g: T var h: T } var nestedGeneric = NestedGenericStruct(a: 1, b: 2, c: LargeGenericStruct(a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8), d: 4, e: 5, f: 6, g: 7, h: 8) @_noLocks func testNestedGenericStruct() -> NestedGenericStruct { return nestedGeneric } var x = 24 let pointerToX = UnsafePointer(&x) @_noLocks func testPointerToX() -> UnsafePointer { return pointerToX } func foo(_ body: () -> (T)) -> T { return body() } func bar(_ body: () -> (T)) -> T { return body() } func baz(t: T) -> T { foo { bar { return t } } } @_noLocks func nestedClosures() -> Int { return baz(t: 42) } @_noAllocation func testInfiniteLoop(_ c: Cl) { c.classMethod() // expected-error {{called function is not known at compile time and can have unpredictable performance}} while true {} } @_noAllocation func testPrecondition(_ count: Int) { precondition(count == 2, "abc") } @_noRuntime func dynamicCastNoRuntime(_ a: AnyObject) -> Cl? { return a as? Cl // expected-error {{dynamic casting can lock or allocate}} } func useExistential(_: T) {} @_noRuntime func openExistentialNoRuntime(_ existential: P) { _openExistential(existential, do: useExistential) // expected-error {{generic function calls can cause metadata allocation or locks}} } @_noExistentials func dynamicCastNoExistential(_ a: AnyObject) -> Cl? { return a as? Cl } @_noExistentials func useOfExistential() -> P { Str(x: 1) // expected-error {{cannot use a value of protocol type 'any P' in '@_noExistential' function}} } @_noExistentials func genericNoExistential() -> some P { Str(x: 1) } @_noRuntime func genericNoRuntime() -> some P { Str(x: 1) } @_noObjCBridging func useOfExistentialNoObjc() -> P { Str(x: 1) } @_noRuntime func useOfExistentialNoRuntime() -> P { Str(x: 1) // expected-error {{Using type 'any P' can cause metadata allocation or locks}} } public struct NonCopyable: ~Copyable { var value: Int } @_noAllocation public func testNonCopyable(_ foo: consuming NonCopyable) { let _ = foo.value } @_noAllocation func matchCEnum(_ variant: c_closed_enum_t) -> Int { switch variant { case .A: return 1 case .B: return 2 case .C: return 5 } } public struct GenericStruct { private var x = 0 private var y: T? @inline(never) init() {} } @_noLocks func testLargeTuple() { typealias SixInt8s = (Int8, Int8, Int8, Int8, Int8, Int8) _ = GenericStruct() } struct Ptr { public var p: UnsafeMutablePointer @_noAllocation init(p: UnsafeMutablePointer) { self.p = p } } struct NonCopyableStruct: ~Copyable { func foo() {} } @_noLocks func testNonCopyable() { let t = NonCopyableStruct() t.foo() } public struct RawLayoutWrapper: ~Copyable { private let x = RawLayout() @_noLocks func testit() { x.test() } } @_rawLayout(like: T) public struct RawLayout: ~Copyable { public func test() {} } func takesClosure(_: () -> ()) {} @_noLocks func testClosureExpression(_ t: T) { takesClosure { // expected-error@-1 {{generic closures or local functions can cause metadata allocation or locks}} _ = T.self } } @_noLocks func testLocalFunction(_ t: T) { func localFunc() { _ = T.self } takesClosure(localFunc) // expected-error@-1 {{generic closures or local functions can cause metadata allocation or locks}} } func takesGInt(_ x: G) {} struct G {} extension G where T == Int { @_noAllocation func method() { takesClosure { takesGInt(self) // OK } } }