Merge pull request #17019 from slavapestov/never-fixes-4.2

Fix various bogus unreachable code warnings [4.2]
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index ccc7adb..55154c3 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -3978,7 +3978,7 @@
            getRepresentation() == SILFunctionTypeRepresentation::Thick;
   }
 
-  bool isNoReturnFunction(); // Defined in SILType.cpp
+  bool isNoReturnFunction() const; // Defined in SILType.cpp
 
   class ABICompatibilityCheckResult {
     friend class SILFunctionType;
diff --git a/lib/SIL/SILType.cpp b/lib/SIL/SILType.cpp
index e2160c5..a219de5 100644
--- a/lib/SIL/SILType.cpp
+++ b/lib/SIL/SILType.cpp
@@ -450,8 +450,13 @@
   return false;
 }
 
-bool SILFunctionType::isNoReturnFunction() {
-  return getDirectFormalResultsType().getSwiftRValueType()->isUninhabited();
+bool SILFunctionType::isNoReturnFunction() const {
+  for (unsigned i = 0, e = getNumResults(); i < e; ++i) {
+    if (getResults()[i].getType()->isUninhabited())
+      return true;
+  }
+
+  return false;
 }
 
 #ifndef NDEBUG
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 32b3919..5c667b8 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -4255,6 +4255,9 @@
   // Pop the argument scope.
   argScope.pop();
 
+  if (substFnType->isNoReturnFunction())
+    loc.markAutoGenerated();
+
   // Explode the direct results.
   SILFunctionConventions substFnConv(substFnType, SGM.M);
   SmallVector<ManagedValue, 4> directResults;
diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp
index 1fd7dd5..d5df851 100644
--- a/lib/SILGen/SILGenLValue.cpp
+++ b/lib/SILGen/SILGenLValue.cpp
@@ -433,6 +433,8 @@
                    ManagedValue base,
                    MaterializedLValue materialized,
                    bool isFinal) override {
+      loc.markAutoGenerated();
+
       assert(base.isLValue());
       SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
     }
@@ -1565,6 +1567,8 @@
                    ManagedValue base,
                    MaterializedLValue materialized,
                    bool isFinal) override {
+      loc.markAutoGenerated();
+
       // If this is final, we can consume the owner (stored as
       // 'base').  If it isn't, we actually need to retain it, because
       // we've still got a release active.
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index eca2a26..53e2c37 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -3416,7 +3416,12 @@
   F.setBare(IsBare);
 
   SILLocation loc(witness.getDecl());
-  FullExpr scope(Cleanups, CleanupLocation::get(loc));
+  loc.markAutoGenerated();
+
+  CleanupLocation cleanupLoc(witness.getDecl());
+  cleanupLoc.markAutoGenerated();
+
+  FullExpr scope(Cleanups, cleanupLoc);
   FormalEvaluationScope formalEvalScope(*this);
 
   auto witnessKind = getWitnessDispatchKind(witness);
@@ -3493,7 +3498,7 @@
   SILValue reqtResultValue = resultPlanner.execute(witnessResultValue);
 
   scope.pop();
-  B.createReturn(CleanupLocation::get(loc), reqtResultValue);
+  B.createReturn(loc, reqtResultValue);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/SILGen/SILGenStmt.cpp b/lib/SILGen/SILGenStmt.cpp
index a24236b..372f9b1 100644
--- a/lib/SILGen/SILGenStmt.cpp
+++ b/lib/SILGen/SILGenStmt.cpp
@@ -404,6 +404,9 @@
   if (!S->hasResult())
     // Void return.
     SGF.Cleanups.emitBranchAndCleanups(SGF.ReturnDest, Loc);
+  else if (S->getResult()->getType()->isUninhabited())
+    // Never return.
+    SGF.emitIgnoredExpr(S->getResult());
   else
     SGF.emitReturnExpr(Loc, S->getResult());
 }
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
index 751b88e..a10d284 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
@@ -423,6 +423,20 @@
     if (BI->getModule().isNoReturnBuiltinOrIntrinsic(BI->getName()))
       return BI;
   }
+
+  // These appear in accessors for stored properties with uninhabited
+  // type. Since a type containing an uninhabited stored property is
+  // itself uninhabited, we treat these identically to fatalError(), etc.
+  if (auto *SEI = dyn_cast<StructExtractInst>(I)) {
+    if (SEI->getType().getASTType()->isUninhabited())
+      return SEI;
+  }
+
+  if (auto *SEAI = dyn_cast<StructElementAddrInst>(I)) {
+    if (SEAI->getType().getASTType()->isUninhabited())
+      return SEAI;
+  }
+
   return nullptr;
 }
 
diff --git a/test/SILOptimizer/specialize.sil b/test/SILOptimizer/specialize.sil
index 6a655d4..09aae2d 100644
--- a/test/SILOptimizer/specialize.sil
+++ b/test/SILOptimizer/specialize.sil
@@ -630,9 +630,7 @@
   %6 = function_ref @action_thunk : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error)
   %7 = partial_apply %6(%5) : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error)
   %8 = apply [nothrow] %1<Never>(%2, %7) : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
-  dealloc_stack %2 : $*Never
-  %12 = tuple ()
-  return %12 : $()
+  unreachable
 } // end sil function 'testGenericClosureSpecialization'
 
 // Test a specialization of a self-recursive generic closure.
diff --git a/test/SILOptimizer/unreachable_code.swift b/test/SILOptimizer/unreachable_code.swift
index af5db68..6e5051b 100644
--- a/test/SILOptimizer/unreachable_code.swift
+++ b/test/SILOptimizer/unreachable_code.swift
@@ -330,9 +330,14 @@
 // We should not report unreachable code inside protocol witness thunks
 
 protocol Fooable {
+  init()
   func foo() -> Never
 }
 struct Foo: Fooable {
+  init() { // no-warning
+    fatalError()
+  }
+
   func foo() -> Never { // no-warning
     while true {}
   }
@@ -340,13 +345,66 @@
 
 // We should not report unreachable code inside vtable thunks
 class Base {
+  required init(x: Int) {
+    fatalError()
+  }
+
   func foo(x: Int) -> Never {
     while true {}
   }
 }
 
 class Derived : Base {
+  required init(x: Int?) {
+    fatalError()
+  }
+
   override func foo(x: Int?) -> Never {
     while true {}
   }
 }
+
+// Inout writeback
+func takesInOut(value: inout SillyStruct) -> Never {
+  while true {}
+}
+
+struct SillyStruct {
+  mutating func mutatingMethod() -> Never {
+    takesInOut(value: &self)
+  }
+}
+
+// This triggers various problems
+public func genericMightBeNever<R>(
+  _ body: () -> R) -> R {
+  while true {}
+
+}
+
+func sillyGenericExample() -> Never {
+  return genericMightBeNever {
+    return genericMightBeNever {
+      return fatalError()
+    }
+  }
+}
+
+// https://bugs.swift.org/browse/SR-7472
+
+protocol P {
+    static var theThing: Self { get }
+}
+
+extension Never : P {
+    static var theThing: Never { return fatalError() }
+}
+
+func test<T: P>(_ type: T.Type) -> T {
+    return type.theThing
+}
+
+func f(i: Int?) {
+    guard i != nil else { Never.theThing }
+    guard i != nil else { test(Never.self) }
+}