Merge pull request #7533 from adrian-prantl/30520286

Fix a bug in GenericCloner causing an LLVM assertion
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index cd344f0..f4afe92 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1789,6 +1789,12 @@
       continue;
     }
 
+    // Look through covariant return expressions.
+    if (auto covariantExpr
+          = dyn_cast<CovariantReturnConversionExpr>(candidate)) {
+      candidate = covariantExpr->getSubExpr();
+      continue;
+    }
     break;
   }
 
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index 7b1cfe4..5f836c3 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -2724,9 +2724,12 @@
 
         auto member = Impl.importDecl(nd, getActiveSwiftVersion());
         if (!member) {
-          // We don't know what this field is. Assume it may be important in C.
-          hasUnreferenceableStorage = true;
-          hasMemberwiseInitializer = false;
+          if (!isa<clang::TypeDecl>(nd)) {
+            // We don't know what this field is.
+            // Assume it may be important in C.
+            hasUnreferenceableStorage = true;
+            hasMemberwiseInitializer = false;
+          }
           continue;
         }
 
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index 1f37744..631a1ea 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -473,11 +473,19 @@
                            v.getCleanup());
     }
 
-    // Upcast to a superclass.
-    return ManagedValue(SGF.B.createUpcast(Loc,
-                                           v.getValue(),
-                                           loweredResultTy),
-                        v.getCleanup());
+    if (outputSubstType->isExactSuperclassOf(inputSubstType, nullptr)) {
+      // Upcast to a superclass.
+      return ManagedValue(SGF.B.createUpcast(Loc,
+                                             v.getValue(),
+                                             loweredResultTy),
+                          v.getCleanup());
+    } else {
+      // Unchecked-downcast to a covariant return type.
+      assert(inputSubstType->isExactSuperclassOf(outputSubstType, nullptr)
+             && "should be inheritance relationship between input and output");
+      return SGF.emitManagedRValueWithCleanup(
+        SGF.B.createUncheckedRefCast(Loc, v.forward(SGF), loweredResultTy));      
+    }
   }
 
   //  - upcasts from an archetype
diff --git a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
index 388644d..294654c 100644
--- a/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
+++ b/lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
@@ -1129,8 +1129,13 @@
       LocExpr = TE->getSubExpr();
     else if (auto *FVE = dyn_cast<ForceValueExpr>(LocExpr))
       LocExpr = FVE->getSubExpr();
- }
+    
+  }
 
+  // Look through covariant return, if any.
+  if (auto CRE = dyn_cast<CovariantReturnConversionExpr>(LocExpr))
+    LocExpr = CRE->getSubExpr();
+  
   // This is a self.init call if structured like this:
   //
   // (call_expr type='SomeClass'
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index 17839e6..2c17be6 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -1378,7 +1378,8 @@
 
     /// \brief Build a new reference to another constructor.
     Expr *buildOtherConstructorRef(Type openedFullType,
-                                   ConstructorDecl *ctor, DeclNameLoc loc,
+                                   ConstructorDecl *ctor, Expr *base,
+                                   DeclNameLoc loc,
                                    ConstraintLocatorBuilder locator,
                                    bool implicit) {
       auto &tc = cs.getTypeChecker();
@@ -1416,8 +1417,21 @@
                                    resultFnTy->getExtInfo());
 
       // Build the constructor reference.
-      return cs.cacheType(
+      Expr *ctorRef = cs.cacheType(
           new (ctx) OtherConstructorDeclRefExpr(ref, loc, implicit, resultTy));
+
+      // Wrap in covariant `Self` return if needed.
+      if (selfTy->hasReferenceSemantics()) {
+        auto covariantTy = resultTy
+          ->replaceCovariantResultType(base->getType()
+                                           ->getLValueOrInOutObjectType(),
+                                       ctor->getNumParameterLists());
+        if (!covariantTy->isEqual(resultTy))
+          ctorRef = cs.cacheType(
+               new (ctx) CovariantFunctionConversionExpr(ctorRef, covariantTy));
+      }
+
+      return ctorRef;
     }
 
     /// Bridge the given value (which is an error type) to NSError.
@@ -2452,7 +2466,7 @@
       }
 
       // Build a partial application of the delegated initializer.
-      Expr *ctorRef = buildOtherConstructorRef(openedType, ctor, nameLoc,
+      Expr *ctorRef = buildOtherConstructorRef(openedType, ctor, base, nameLoc,
                                                ctorLocator, implicit);
       auto *call = new (cs.getASTContext()) DotSyntaxCallExpr(ctorRef, dotLoc,
                                                               base);
diff --git a/test/ClangImporter/ctypes_parse.swift b/test/ClangImporter/ctypes_parse.swift
index 5a1c06c..eac83eb 100644
--- a/test/ClangImporter/ctypes_parse.swift
+++ b/test/ClangImporter/ctypes_parse.swift
@@ -235,3 +235,9 @@
   }
   hasVaList(nil) // expected-error {{nil is not compatible with expected argument type 'CVaListPointer'}}
 }
+
+func testNestedForwardDeclaredStructs() {
+  // Check that we still have a memberwise initializer despite the forward-
+  // declared nested type. rdar://problem/30449400
+  _ = StructWithForwardDeclaredStruct(ptr: nil)
+}
diff --git a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h
index d79aebb..758739b 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/ctypes.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/ctypes.h
@@ -123,6 +123,10 @@
   double y;
 };
 
+struct StructWithForwardDeclaredStruct {
+  struct ForwardDeclaredStruct *ptr;
+};
+
 //===---
 // Typedefs.
 //===---
diff --git a/test/SILGen/witness-init-requirement-with-base-class-init.swift b/test/SILGen/witness-init-requirement-with-base-class-init.swift
new file mode 100644
index 0000000..cfd3176
--- /dev/null
+++ b/test/SILGen/witness-init-requirement-with-base-class-init.swift
@@ -0,0 +1,22 @@
+// RUN: %target-swift-frontend -emit-silgen %s | %FileCheck %s
+// RUN: %target-swift-frontend -emit-sil -verify %s
+
+protocol BestFriend: class {
+  init()
+  static func create() -> Self
+}
+
+class Animal {
+  required init(species: String) {}
+
+  static func create() -> Self { return self.init() }
+  required convenience init() { self.init(species: "\(type(of: self))") }
+}
+
+class Dog: Animal, BestFriend {}
+// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC4main3DogS_10BestFriendS_FS1_CfT_x
+// CHECK:         [[SELF:%.*]] = apply
+// CHECK:         unchecked_ref_cast [[SELF]] : $Animal to $Dog
+// CHECK-LABEL: sil hidden [transparent] [thunk] @_TTWC4main3DogS_10BestFriendS_ZFS1_6createfT_x
+// CHECK:         [[SELF:%.*]] = apply
+// CHECK:         unchecked_ref_cast [[SELF]] : $Animal to $Dog
diff --git a/test/decl/init/Inputs/c-func-member-init.h b/test/decl/init/Inputs/c-func-member-init.h
new file mode 100644
index 0000000..431b7c8
--- /dev/null
+++ b/test/decl/init/Inputs/c-func-member-init.h
@@ -0,0 +1,6 @@
+__attribute__((objc_root_class))
+@interface MyObject
+@end
+
+__attribute__((swift_name("MyObject.init(id:)")))
+MyObject *_Nonnull my_object_create(int id);
diff --git a/test/decl/init/delegate-to-c-func-imported-as-member.swift b/test/decl/init/delegate-to-c-func-imported-as-member.swift
new file mode 100644
index 0000000..922c32f
--- /dev/null
+++ b/test/decl/init/delegate-to-c-func-imported-as-member.swift
@@ -0,0 +1,8 @@
+// RUN: %target-swift-frontend -emit-sil -verify -import-objc-header %S/Inputs/c-func-member-init.h %s
+// REQUIRES: objc_interop
+
+extension MyObject {
+  convenience init() {
+    self.init(id: 1738)
+  }
+}
diff --git a/test/decl/init/nonnull-delegate-to-nullable-in-base-class.swift b/test/decl/init/nonnull-delegate-to-nullable-in-base-class.swift
new file mode 100644
index 0000000..bd399a7
--- /dev/null
+++ b/test/decl/init/nonnull-delegate-to-nullable-in-base-class.swift
@@ -0,0 +1,20 @@
+// RUN: %target-swift-frontend -emit-sil -verify %s
+
+class Animal {
+    convenience init?(species: String) {
+        self.init()
+    }
+}
+
+class Dog: Animal {
+    var butt = "dog \("butt")"
+
+    convenience init(owner: String) {
+        self.init(species: "Dog")!
+    }
+
+
+}
+
+print(Dog(owner: "John Arbuckle").butt)
+