Skip to content

Commit f847d1b

Browse files
committed
[WIP] DiagnoseLifetimeDependence pass
Prototype diagnostic pass to bootstrap lifetime-dependence infrastructure in Swifty SIL.
1 parent 7646d4d commit f847d1b

File tree

9 files changed

+872
-0
lines changed

9 files changed

+872
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ swift_compiler_sources(Optimizer
1313
ComputeEscapeEffects.swift
1414
ComputeSideEffects.swift
1515
DeadStoreElimination.swift
16+
DiagnoseLifetimeDependence.swift
1617
InitializeStaticGlobals.swift
1718
LetPropertyLowering.swift
1819
ObjectOutliner.swift

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DiagnoseLifetimeDependence.swift

Lines changed: 646 additions & 0 deletions
Large diffs are not rendered by default.

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ private func registerSwiftPasses() {
8888
registerPass(deadStoreElimination, { deadStoreElimination.run($0) })
8989
registerPass(redundantLoadElimination, { redundantLoadElimination.run($0) })
9090
registerPass(earlyRedundantLoadElimination, { earlyRedundantLoadElimination.run($0) })
91+
registerPass(diagnoseLifetimeDependencePass, { diagnoseLifetimeDependencePass.run($0) })
9192

9293
// Instruction passes
9394
registerForSILCombine(BeginCOWMutationInst.self, { run(BeginCOWMutationInst.self, $0) })

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import AST
1314
import SIL
1415
import OptimizerBridging
1516

include/swift/AST/DiagnosticsSIL.def

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,5 +884,16 @@ WARNING(call_site_consumption_yields_race, none,
884884
NOTE(possible_racy_access_site, none,
885885
"access here could race", ())
886886

887+
ERROR(lifetime_value_outside_scope, none,
888+
"lifetime-dependent value escapes its scope", ())
889+
ERROR(lifetime_variable_outside_scope, none,
890+
"lifetime-dependent variable '%0' escapes its scope", (Identifier))
891+
NOTE(lifetime_outside_scope_parent, none,
892+
"it depends on the lifetime of this parent value", ())
893+
NOTE(lifetime_outside_scope_use, none,
894+
"this use of the lifetime-dependent value is out of scope", ())
895+
NOTE(lifetime_outside_scope_escape, none,
896+
"this use causes the lifetime-dependent value to escape", ())
897+
887898
#define UNDEFINE_DIAGNOSTIC_MACROS
888899
#include "DefineDiagnosticMacros.h"

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ PASS(DiagnoseInfiniteRecursion, "diagnose-infinite-recursion",
192192
"Diagnose Infinitely-Recursive Code")
193193
PASS(DiagnoseInvalidEscapingCaptures, "diagnose-invalid-escaping-captures",
194194
"Diagnose Invalid Escaping Captures")
195+
SWIFT_FUNCTION_PASS(DiagnoseLifetimeDependence, "diagnose-lifetime-dependence",
196+
"Diagnose Lifetime Dependence")
195197
PASS(DiagnoseLifetimeIssues, "diagnose-lifetime-issues",
196198
"Diagnose Lifetime Issues")
197199
PASS(DiagnoseStaticExclusivity, "diagnose-static-exclusivity",

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ static void addDefiniteInitialization(SILPassPipelinePlan &P) {
117117
static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
118118
P.startPipeline("Mandatory Diagnostic Passes + Enabling Optimization Passes");
119119
P.addDiagnoseInvalidEscapingCaptures();
120+
P.addDiagnoseLifetimeDependence();
120121
P.addReferenceBindingTransform();
121122
P.addDiagnoseStaticExclusivity();
122123
P.addNestedSemanticFunctionCheck();
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-sil %s -o /dev/null -verify
2+
3+
public class C {
4+
public let i: Int64
5+
6+
init() {
7+
self.i = 0
8+
}
9+
}
10+
11+
@_nonEscapable public struct NoEscStructI {
12+
public let i: Int64
13+
14+
@_unsafeNonEscapableResult
15+
init() {
16+
self.i = 0
17+
}
18+
19+
@_unsafeNonEscapableResult
20+
static func make() -> NoEscStructI {
21+
return NoEscStructI()
22+
}
23+
}
24+
25+
@_nonEscapable public struct NoEscStructC {
26+
public let c: C
27+
28+
// FIXME: resultDependsOn
29+
@_unsafeNonEscapableResult
30+
init(c: C) {
31+
self.c = c
32+
}
33+
}
34+
35+
@_nonEscapable public class NoEscClass {
36+
@_unsafeNonEscapableResult
37+
init() {}
38+
}
39+
40+
// =============================================================================
41+
// Expected Pass
42+
43+
// -----------------------------------------------------------------------------
44+
// NonEscapingScope.orphan
45+
46+
// Returns trivial 'nes.i', which is not an escape.
47+
//
48+
// ### Diagnosing lifetime dependence on scope: orphan( %2 = apply %1(%0) : $@convention(method) (@thin NES.Type) -> NES
49+
func createNoEscStructI() -> Int64 {
50+
let nes = NoEscStructI.make()
51+
return nes.i
52+
}
53+
54+
// -----------------------------------------------------------------------------
55+
// NonEscapingScope.caller
56+
57+
// Returns a nontrivial member, which is an escape.
58+
//
59+
func createArgNoEscStructCArg(c: C) -> C {
60+
let nes = NoEscStructC(c: c)
61+
return nes.c
62+
}
63+
64+
func passNoEscStructI(nes: NoEscStructI) -> Int64 {
65+
return nes.i
66+
}
67+
68+
func passNoEscStructILet(nes: NoEscStructI) -> Int64 {
69+
let nes = nes
70+
return nes.i
71+
}
72+
73+
// =============================================================================
74+
// Expected Fail
75+
76+
// -----------------------------------------------------------------------------
77+
// NonEscapingScope.orphan
78+
79+
// Escapes a new non-escapable orphan.
80+
//
81+
func createNoEscStructIReturn() -> NoEscStructI {
82+
return NoEscStructI.make() // expected-error {{lifetime-dependent value escapes its scope}}
83+
// expcted-note @-1 {{this use of the lifetime-dependent value is out of scope}}
84+
}
85+
86+
// Escapes a new non-escapable orphan.
87+
//
88+
// FIXME: diagnostic should be escapes its scope
89+
func createNoEscStructILetReturn() -> NoEscStructI {
90+
let nes = NoEscStructI.make()
91+
return nes
92+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-sil %s -o /dev/null -verify
2+
3+
// REQUIRES: diagnose_lifetime_dependence
4+
5+
public class C {
6+
public let i: Int64
7+
8+
init() {
9+
self.i = 0
10+
}
11+
}
12+
13+
@_nonEscapable public struct NoEscStructI {
14+
public let i: Int64
15+
16+
@_unsafeNonEscapableResult
17+
init() {
18+
self.i = 0
19+
}
20+
21+
@_unsafeNonEscapableResult
22+
static func make() -> NoEscStructI {
23+
return NoEscStructI()
24+
}
25+
}
26+
27+
@_nonEscapable public struct NoEscStructC {
28+
public let c: C
29+
30+
// FIXME: resultDependsOn
31+
@_unsafeNonEscapableResult
32+
init(c: C) {
33+
self.c = c
34+
}
35+
}
36+
37+
@_nonEscapable public class NoEscClass {
38+
@_unsafeNonEscapableResult
39+
init() {}
40+
}
41+
42+
// =============================================================================
43+
// Unexpected Pass
44+
45+
// -----------------------------------------------------------------------------
46+
// NonEscapingScope.caller
47+
48+
func passNoEscStructIReturn(nes: NoEscStructI) -> NoEscStructI {
49+
return nes
50+
}
51+
52+
// =============================================================================
53+
// Expected Fail - Incorrect Diagnostic
54+
55+
// FIXME: do not consider the assigns escapes. Only the return escapes.
56+
func createNoEscStructIVarReturn() -> NoEscStructI {
57+
var nes = NoEscStructI.make() // expected-error {{lifetime-dependent value escapes its scope}}
58+
// expcted-note @-1 {{this use causes the lifetime-dependent value to escape}}
59+
nes = NoEscStructI.make() // expected-error {{lifetime-dependent value escapes its scope}}
60+
// expcted-note @-1 {{this use causes the lifetime-dependent value to escape}}
61+
return nes
62+
}
63+
64+
// =============================================================================
65+
// Unexpected Fail
66+
67+
// -----------------------------------------------------------------------------
68+
// NonEscapingScope.orphan
69+
70+
// Returns trivial 'nes.i', which is not an escape.
71+
//
72+
// FIXME: do not consider the assigns escapes
73+
func createNoEscStructIVar() -> Int64 {
74+
var nes = NoEscStructI.make()
75+
nes = NoEscStructI.make()
76+
return nes.i
77+
}
78+
79+
// -----------------------------------------------------------------------------
80+
// NonEscapingScope.caller
81+
82+
// FIXME: do not consider the assigns escapes
83+
func passNoEscStructIVar(nes: inout NoEscStructI) -> Int64 {
84+
nes = NoEscStructI.make()
85+
return nes.i
86+
}
87+
88+
// -----------------------------------------------------------------------------
89+
// NonEscapingScope.owned
90+
91+
// 'c' is an owned scope.
92+
// 'nes.c' is used within 'c'.
93+
//
94+
// FIXME: nec.c.i should not be an escaping use.
95+
func createNewNoEscStructC() -> Int64 {
96+
let c = C()
97+
let nes = NoEscStructC(c: c)
98+
return nes.c.i
99+
}
100+
101+
// 'c' is an owned scope.
102+
// 'nes.c' escapes via return.
103+
func createNewNoEscStructCReturn() -> C {
104+
let c = C()
105+
let nes = NoEscStructC(c: c)
106+
return nes.c
107+
}
108+
109+
// -----------------------------------------------------------------------------
110+
// NonEscapingScope.scoped
111+
112+
func createNoEscStructCAccess() -> C {
113+
var c = C()
114+
_ = { c = C() }
115+
let nes = NoEscStructC(c: c)
116+
return nes.c
117+
}

0 commit comments

Comments
 (0)