Merge pull request #12445 from slavapestov/di-self-consumed-analysis-volume-1
DI: self-consumed analysis rework, volume 1
diff --git a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
index 1c006e0..9c1d3ae 100644
--- a/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
+++ b/lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
@@ -521,6 +521,8 @@
private:
+ void emitSelfConsumedDiagnostic(SILInstruction *Inst);
+
LiveOutBlockState &getBlockInfo(SILBasicBlock *BB) {
return PerBlockInfo.insert({BB,
LiveOutBlockState(TheMemory.NumElements)}).first->second;
@@ -920,18 +922,23 @@
}
}
+void LifetimeChecker::emitSelfConsumedDiagnostic(SILInstruction *Inst) {
+ if (!shouldEmitError(Inst))
+ return;
+
+ diagnose(Module, Inst->getLoc(),
+ diag::self_inside_catch_superselfinit,
+ (unsigned)TheMemory.isDelegatingInit());
+}
+
void LifetimeChecker::handleStoreUse(unsigned UseID) {
DIMemoryUse &InstInfo = Uses[UseID];
- if (getSelfConsumedAtInst(InstInfo.Inst) != DIKind::No) {
- // FIXME: more specific diagnostics here, handle this case gracefully below.
- if (!shouldEmitError(InstInfo.Inst))
+ if (TheMemory.isAnyInitSelf()) {
+ if (getSelfConsumedAtInst(InstInfo.Inst) != DIKind::No) {
+ emitSelfConsumedDiagnostic(InstInfo.Inst);
return;
-
- diagnose(Module, InstInfo.Inst->getLoc(),
- diag::self_inside_catch_superselfinit,
- (unsigned)TheMemory.isDelegatingInit());
- return;
+ }
}
// Determine the liveness state of the element that we care about.
@@ -1025,13 +1032,7 @@
// before the "address" is passed as an l-value.
if (!isInitializedAtUse(Use, &IsSuperInitDone, &FailedSelfUse)) {
if (FailedSelfUse) {
- // FIXME: more specific diagnostics here, handle this case gracefully below.
- if (!shouldEmitError(Use.Inst))
- return;
-
- diagnose(Module, Use.Inst->getLoc(),
- diag::self_inside_catch_superselfinit,
- (unsigned)TheMemory.isDelegatingInit());
+ emitSelfConsumedDiagnostic(Use.Inst);
return;
}
@@ -1133,13 +1134,7 @@
auto Inst = Use.Inst;
if (FailedSelfUse) {
- // FIXME: more specific diagnostics here, handle this case gracefully below.
- if (!shouldEmitError(Inst))
- return;
-
- diagnose(Module, Inst->getLoc(),
- diag::self_inside_catch_superselfinit,
- (unsigned)TheMemory.isDelegatingInit());
+ emitSelfConsumedDiagnostic(Inst);
return;
}
@@ -1500,13 +1495,7 @@
SILInstruction *Inst = Use.Inst;
if (FailedSelfUse) {
- // FIXME: more specific diagnostics here, handle this case gracefully below.
- if (!shouldEmitError(Inst))
- return;
-
- diagnose(Module, Inst->getLoc(),
- diag::self_inside_catch_superselfinit,
- (unsigned)TheMemory.isDelegatingInit());
+ emitSelfConsumedDiagnostic(Inst);
return;
}
@@ -1664,16 +1653,11 @@
void LifetimeChecker::handleSelfInitUse(DIMemoryUse &InstInfo) {
auto *Inst = InstInfo.Inst;
+ assert(TheMemory.isAnyInitSelf());
assert(TheMemory.getType()->hasReferenceSemantics());
if (getSelfConsumedAtInst(Inst) != DIKind::No) {
- // FIXME: more specific diagnostics here, handle this case gracefully below.
- if (!shouldEmitError(Inst))
- return;
-
- diagnose(Module, Inst->getLoc(),
- diag::self_inside_catch_superselfinit,
- (unsigned)TheMemory.isDelegatingInit());
+ emitSelfConsumedDiagnostic(Inst);
return;
}
@@ -1899,8 +1883,10 @@
isa<DestroyAddrInst>(Release));
auto Availability = getLivenessAtInst(Release, 0, TheMemory.NumElements);
- DIKind SelfConsumed =
- getSelfConsumedAtInst(Release);
+ DIKind SelfConsumed = DIKind::No;
+
+ if (TheMemory.isAnyInitSelf())
+ SelfConsumed = getSelfConsumedAtInst(Release);
if (SelfConsumed == DIKind::Yes) {
// We're in an error path after performing a self.init or super.init
@@ -2643,12 +2629,14 @@
bool *FailedSelfUse) {
if (FailedSelfUse) *FailedSelfUse = false;
if (SuperInitDone) *SuperInitDone = true;
-
- // If the self.init() or super.init() call threw an error and
- // we caught it, self is no longer available.
- if (getSelfConsumedAtInst(Use.Inst) != DIKind::No) {
- if (FailedSelfUse) *FailedSelfUse = true;
- return false;
+
+ if (TheMemory.isAnyInitSelf()) {
+ // If the self.init() or super.init() call threw an error and
+ // we caught it, self is no longer available.
+ if (getSelfConsumedAtInst(Use.Inst) != DIKind::No) {
+ if (FailedSelfUse) *FailedSelfUse = true;
+ return false;
+ }
}
// Determine the liveness states of the elements that we care about.
diff --git a/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift b/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift
index 5270f34..eac70a5 100644
--- a/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift
+++ b/test/SILOptimizer/definite_init_failable_initializers_diagnostics.swift
@@ -51,12 +51,61 @@
} catch {}
} // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+ init(invalidEscapeDesignated2: ()) throws {
+ x = 10
+ y = 10
+ do {
+ try super.init()
+ } catch {
+ try super.init() // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+ }
+ } // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+
+ init(invalidEscapeDesignated3: ()) {
+ x = 10
+ y = 10
+ do {
+ try super.init()
+ } catch {
+ print(self.x) // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+ self.y = 20 // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+ }
+ } // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+
+ init(invalidEscapeDesignated4: ()) throws {
+ x = 10
+ y = 10
+ do {
+ try super.init()
+ } catch let e {
+ print(self.x) // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
+ throw e
+ }
+ }
+
convenience init(invalidEscapeConvenience: ()) {
do {
try self.init()
} catch {}
} // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
+ convenience init(invalidEscapeConvenience2: ()) throws {
+ do {
+ try self.init()
+ } catch {
+ try self.init() // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
+ }
+ } // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
+
+ convenience init(invalidEscapeConvenience3: ()) throws {
+ do {
+ try self.init()
+ } catch let e {
+ print(self) // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
+ throw e
+ }
+ }
+
init(noEscapeDesignated: ()) throws {
x = 10
y = 10
diff --git a/test/SILOptimizer/definite_init_markuninitialized_derivedself.sil b/test/SILOptimizer/definite_init_markuninitialized_derivedself.sil
index 3602df3..65934f0 100644
--- a/test/SILOptimizer/definite_init_markuninitialized_derivedself.sil
+++ b/test/SILOptimizer/definite_init_markuninitialized_derivedself.sil
@@ -121,7 +121,7 @@
%14 = function_ref @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars
%15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars // expected-error {{property 'self.a' not initialized at super.init call}}
%16 = unchecked_ref_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars
- assign %16 to %3 : $*DerivedClassWithIVars
+ store %16 to [init] %3 : $*DerivedClassWithIVars
%18 = load [copy] %3 : $*DerivedClassWithIVars
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <DerivedClassWithIVars>
@@ -272,7 +272,7 @@
// Call super.init.
%15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars
%16 = unchecked_ref_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars
- assign %16 to %3 : $*DerivedClassWithIVars
+ store %16 to [init] %3 : $*DerivedClassWithIVars
%18 = load [copy] %3 : $*DerivedClassWithIVars
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <DerivedClassWithIVars>
return %18 : $DerivedClassWithIVars