| // RUN: %target-swiftc_driver -O -Rpass-missed=sil-opt-remark-gen -Xllvm -sil-disable-pass=FunctionSignatureOpts -emit-sil %s -o /dev/null -Xfrontend -verify |
| // REQUIRES: optimized_stdlib,swift_stdlib_no_asserts |
| |
| public class Klass {} |
| |
| // TODO: Change global related code to be implicit/autogenerated (as |
| // appropriate) so we don't emit this remark. |
| public var global = Klass() // expected-remark {{heap allocated ref of type 'Klass'}} |
| |
| @inline(never) |
| public func getGlobal() -> Klass { |
| return global // expected-remark @:5 {{retain of type 'Klass'}} |
| // expected-note @-5:12 {{of 'global'}} |
| } |
| |
| // Make sure that the retain msg is at the beginning of the print and the |
| // releases are the end of the print. |
| // |
| // The heap allocated ref is for the temporary array and the release that is |
| // unannotated is for that array as well. We make sure that the heap allocated |
| // ref is on the argument that necessitated its creation. |
| public func useGlobal() { |
| let x = getGlobal() |
| print(x) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-3:9 {{of 'x'}} |
| // expected-remark @-3:12 {{release of type}} |
| // expected-remark @-4:12 {{release of type 'Klass'}} |
| // expected-note @-6:9 {{of 'x'}} |
| } |
| |
| public enum TrivialState { |
| case first |
| case second |
| case third |
| } |
| |
| struct StructWithOwner { |
| var owner = Klass() |
| var state = TrivialState.first |
| } |
| |
| func printStructWithOwner(x : StructWithOwner) { |
| print(x) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1 {{retain of type 'Klass'}} |
| // expected-note @-3:27 {{of 'x.owner'}} |
| // expected-remark @-3:12 {{release of type}} |
| } |
| |
| func printStructWithOwnerOwner(x : StructWithOwner) { |
| print(x.owner) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1 {{retain of type 'Klass'}} |
| // expected-note @-3:32 {{of 'x.owner'}} |
| // expected-remark @-3:18 {{release of type}} |
| } |
| |
| func returnStructWithOwnerOwner(x: StructWithOwner) -> Klass { |
| return x.owner // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:33 {{of 'x.owner'}} |
| } |
| |
| func callingAnInitializerStructWithOwner(x: Klass) -> StructWithOwner { |
| return StructWithOwner(owner: x) // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:42 {{of 'x'}} |
| } |
| |
| struct KlassPair { |
| var lhs: Klass |
| var rhs: Klass |
| } |
| |
| func printKlassPair(x : KlassPair) { |
| // We pattern match columns to ensure we get retain on the p and release on |
| // the end ')' |
| print(x) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-5:21 {{of 'x.lhs'}} |
| // expected-remark @-3:5 {{retain of type 'Klass'}} |
| // expected-note @-7:21 {{of 'x.rhs'}} |
| // expected-remark @-5:12 {{release of type}} |
| } |
| |
| func printKlassPairLHS(x : KlassPair) { |
| // We print the remarks at the 'p' and at the ending ')'. |
| print(x.lhs) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-4:24 {{of 'x.lhs'}} |
| // expected-remark @-3:16 {{release of type}} |
| } |
| |
| // We put the retain on the return here since it is part of the result |
| // convention. |
| func returnKlassPairLHS(x: KlassPair) -> Klass { |
| return x.lhs // expected-remark @:5 {{retain of type 'Klass'}} |
| // expected-note @-2:25 {{of 'x.lhs'}} |
| } |
| |
| func callingAnInitializerKlassPair(x: Klass, y: Klass) -> KlassPair { |
| return KlassPair(lhs: x, rhs: y) // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:36 {{of 'x'}} |
| // expected-remark @-2:5 {{retain of type 'Klass'}} |
| // expected-note @-4:46 {{of 'y'}} |
| } |
| |
| func printKlassTuplePair(x : (Klass, Klass)) { |
| // We pattern match columns to ensure we get retain on the p and release on |
| // the end ')' |
| print(x) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-5:26 {{of 'x'}} |
| // expected-remark @-3:5 {{retain of type 'Klass'}} |
| // expected-note @-7:26 {{of 'x'}} |
| // expected-remark @-5:12 {{release of type}} |
| } |
| |
| func printKlassTupleLHS(x : (Klass, Klass)) { |
| // We print the remarks at the 'p' and at the ending ')'. |
| print(x.0) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-4:25 {{of 'x'}} |
| // Release on Array<Any> for print. |
| // expected-remark @-4:14 {{release of type}} |
| } |
| |
| func returnKlassTupleLHS(x: (Klass, Klass)) -> Klass { |
| return x.0 // expected-remark @:5 {{retain of type 'Klass'}} |
| // expected-note @-2:26 {{of 'x'}} |
| } |
| |
| func callingAnInitializerKlassTuplePair(x: Klass, y: Klass) -> (Klass, Klass) { |
| return (x, y) // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:41 {{of 'x'}} |
| // expected-remark @-2:5 {{retain of type 'Klass'}} |
| // expected-note @-4:51 {{of 'y'}} |
| } |
| |
| public class SubKlass : Klass { |
| @inline(never) |
| final func doSomething() {} |
| } |
| |
| func lookThroughCast(x: SubKlass) -> Klass { |
| return x as Klass // expected-remark {{retain of type 'SubKlass'}} |
| // expected-note @-2:22 {{of 'x'}} |
| } |
| |
| func lookThroughRefCast(x: Klass) -> SubKlass { |
| return x as! SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:25 {{of 'x'}} |
| } |
| |
| func lookThroughEnum(x: Klass?) -> Klass { |
| return x! // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:22 {{of 'x.some'}} |
| } |
| |
| func castAsQuestion(x: Klass) -> SubKlass? { |
| x as? SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2:21 {{of 'x'}} |
| } |
| |
| func castAsQuestionDiamond(x: Klass) -> SubKlass? { |
| guard let y = x as? SubKlass else { |
| return nil |
| } |
| |
| y.doSomething() |
| return y // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-7:28 {{of 'x'}} |
| } |
| |
| func castAsQuestionDiamondGEP(x: KlassPair) -> SubKlass? { |
| guard let y = x.lhs as? SubKlass else { |
| return nil |
| } |
| |
| y.doSomething() |
| // We eliminate the rhs retain/release. |
| return y // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-8:31 {{of 'x.lhs'}} |
| } |
| |
| // We don't handle this test case as well. |
| func castAsQuestionDiamondGEP2(x: KlassPair) { |
| switch (x.lhs as? SubKlass, x.rhs as? SubKlass) { // expected-remark @:19 {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.lhs'}} |
| // expected-remark @-2:39 {{retain of type 'Klass'}} |
| // expected-note @-4 {{of 'x.rhs'}} |
| case let (.some(x1), .some(x2)): |
| print(x1, x2) // expected-remark @:15 {{heap allocated ref of type}} |
| // expected-remark @-1 {{retain of type 'Optional<SubKlass>'}} |
| // expected-remark @-2 {{retain of type 'Optional<SubKlass>'}} |
| // expected-remark @-3 {{release of type}} |
| // expected-remark @-4 {{release of type 'Optional<SubKlass>'}} |
| // expected-remark @-5 {{release of type 'Optional<SubKlass>'}} |
| case let (.some(x1), nil): |
| print(x1) // expected-remark @:15 {{heap allocated ref of type}} |
| // expected-remark @-1 {{retain of type 'SubKlass'}} |
| // expected-remark @-2 {{release of type}} |
| // expected-remark @-3 {{release of type 'Optional<SubKlass>'}} |
| case let (nil, .some(x2)): |
| print(x2) // expected-remark @:15 {{heap allocated ref of type}} |
| // expected-remark @-1 {{retain of type 'SubKlass'}} |
| // expected-remark @-2 {{release of type}} |
| // expected-remark @-3 {{release of type 'Optional<SubKlass>'}} |
| case (nil, nil): |
| break |
| } |
| } |
| |
| func inoutKlassPairArgument(x: inout KlassPair) -> Klass { |
| return x.lhs // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.lhs'}} |
| } |
| |
| func inoutKlassTuplePairArgument(x: inout (Klass, Klass)) -> Klass { |
| return x.0 // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.0'}} |
| } |
| |
| func inoutKlassOptionalArgument(x: inout Klass?) -> Klass { |
| return x! // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.some'}} |
| } |
| |
| func inoutKlassBangCastArgument(x: inout Klass) -> SubKlass { |
| return x as! SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x'}} |
| } |
| |
| func inoutKlassQuestionCastArgument(x: inout Klass) -> SubKlass? { |
| return x as? SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x'}} |
| } |
| |
| func inoutKlassBangCastArgument2(x: inout Klass?) -> SubKlass { |
| return x as! SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.some'}} |
| } |
| |
| func inoutKlassQuestionCastArgument2(x: inout Klass?) -> SubKlass? { |
| return x as? SubKlass // expected-remark {{retain of type 'Klass'}} |
| // expected-note @-2 {{of 'x.some'}} |
| } |
| |
| // We should have 1x rr remark here on calleeX for storing it into the array to |
| // print. Release is from the array. We don't pattern match it due to the actual |
| // underlying Array type name changing under the hood in between platforms. |
| @inline(__always) |
| func alwaysInlineCallee(_ calleeX: Klass) { |
| print(calleeX) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-3:27 {{of 'calleeX'}} |
| // expected-remark @-3:18 {{release of type}} |
| } |
| |
| // We should have 3x rr remarks here on callerX and none on calleeX. All of the |
| // releases are for the temporary array that we pass into print. |
| // |
| // TODO: Should we print out as notes the whole inlined call stack? |
| func alwaysInlineCaller(_ callerX: Klass) { |
| alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-3:27 {{of 'callerX'}} |
| // expected-remark @-3:31 {{release of type}} |
| print(callerX) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-7:27 {{of 'callerX'}} |
| // expected-remark @-3:18 {{release of type}} |
| alwaysInlineCallee(callerX) // expected-remark @:5 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-11:27 {{of 'callerX'}} |
| // expected-remark @-3:31 {{release of type}} |
| } |
| |
| func allocateValue() { |
| // Remark should be on Klass and note should be on k. |
| let k = Klass() // expected-remark @:13 {{heap allocated ref of type 'Klass'}} |
| // expected-note @-1:9 {{of 'k'}} |
| print(k) // expected-remark @:11 {{heap allocated ref of type}} |
| // expected-remark @-1:5 {{retain of type 'Klass'}} |
| // expected-note @-4:9 {{of 'k'}} |
| // expected-remark @-3:12 {{release of type}} |
| // expected-remark @-4:12 {{release of type 'Klass'}} |
| // expected-note @-7:9 {{of 'k'}} |
| } |