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