Merge pull request #9407 from slavapestov/use-objc-msgsend-for-overrides-of-imported-methods

Use objc_msgSend() for overrides of imported methods [4.0]
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 69c1412..68bec97 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -2139,6 +2139,8 @@
   }
   if (superclassCtor->isRequired())
     ctor->getAttrs().add(new (tc.Context) RequiredAttr(/*IsImplicit=*/true));
+  if (superclassCtor->isDynamic())
+    ctor->getAttrs().add(new (tc.Context) DynamicAttr(/*IsImplicit*/true));
 
   // Wire up the overrides.
   ctor->getAttrs().add(new (tc.Context) OverrideAttr(/*IsImplicit=*/true));
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 26b31cb..bf17898 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -2472,7 +2472,8 @@
 ///
 /// This occurs when
 /// - it is implied by an attribute like @NSManaged
-/// - we need to dynamically dispatch to a method in an extension.
+/// - when we have an override of an imported method
+/// - we need to dynamically dispatch to a method in an extension
 ///
 /// FIXME: The latter reason is a hack. We should figure out how to safely
 /// put extension methods into the class vtable.
@@ -2485,11 +2486,15 @@
   if (!D->isObjC() || D->hasClangNode())
     return;
 
+  bool overridesImportedMethod =
+    (D->getOverriddenDecl() &&
+     D->getOverriddenDecl()->hasClangNode());
+
   // Only introduce 'dynamic' on declarations...
   bool isNSManaged = D->getAttrs().hasAttribute<NSManagedAttr>();
   if (!isa<ExtensionDecl>(D->getDeclContext())) {
     // ...and in classes on decls marked @NSManaged.
-    if (!isNSManaged)
+    if (!isNSManaged && !overridesImportedMethod)
       return;
   }
 
diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift
index 4a15ffd..c33ebb1 100644
--- a/test/SILGen/dynamic.swift
+++ b/test/SILGen/dynamic.swift
@@ -235,6 +235,23 @@
   dynamic override func overriddenByDynamic() {}
 }
 
+class SubclassWithInheritedInits: Foo {
+  // CHECK-LABEL: sil hidden @_T07dynamic26SubclassWithInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         super_method [volatile] {{%.*}} : $SubclassWithInheritedInits, #Foo.init!initializer.1.foreign :
+}
+class GrandchildWithInheritedInits: SubclassWithInheritedInits {
+  // CHECK-LABEL: sil hidden @_T07dynamic28GrandchildWithInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         super_method [volatile] {{%.*}} : $GrandchildWithInheritedInits, #SubclassWithInheritedInits.init!initializer.1.foreign :
+}
+class GrandchildOfInheritedInits: SubclassWithInheritedInits {
+  // Dynamic methods are super-dispatched by objc_msgSend
+  override init(dynamic: Int) {
+    super.init(dynamic: dynamic)
+  }
+  // CHECK-LABEL: sil hidden @_T07dynamic26GrandchildOfInheritedInitsC{{[_0-9a-zA-Z]*}}fc
+  // CHECK:         super_method [volatile] {{%.*}} : $GrandchildOfInheritedInits, #SubclassWithInheritedInits.init!initializer.1.foreign :
+}
+
 // CHECK-LABEL: sil hidden @_T07dynamic20nativeMethodDispatchyyF : $@convention(thin) () -> ()
 func nativeMethodDispatch() {
   // CHECK: function_ref @_T07dynamic3{{[_0-9a-zA-Z]*}}fC
@@ -508,6 +525,25 @@
 // CHECK:   #Foo.overriddenByDynamic!1: {{.*}} : public _T07dynamic8SubclassC19overriddenByDynamic{{[_0-9a-zA-Z]*}}FTD
 // CHECK: }
 
+// Check vtables for implicitly-inherited initializers
+// CHECK-LABEL: sil_vtable SubclassWithInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic26SubclassWithInheritedInitsCACSi6native_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic26SubclassWithInheritedInitsCACSi4objc_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
+// CHECK-LABEL: sil_vtable GrandchildWithInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic28GrandchildWithInheritedInitsCACSi6native_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic28GrandchildWithInheritedInitsCACSi4objc_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
+// CHECK-LABEL: sil_vtable GrandchildOfInheritedInits {
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic26GrandchildOfInheritedInitsCACSi6native_tcfc
+// CHECK:   #Foo.init!initializer.1: (Foo.Type) -> (Int) -> Foo : _T07dynamic26GrandchildOfInheritedInitsCACSi4objc_tcfc
+// CHECK-NOT: .init!
+// CHECK: }
+
 // No vtable entry for override of @objc extension property
 // CHECK-LABEL: sil_vtable SubExt {
 // CHECK-NEXT: #BaseExt.init!initializer.1: (BaseExt.Type) -> () -> BaseExt : _T07dynamic6SubExtCACycfc // dynamic.SubExt.init() -> dynamic.SubExt
diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift
index 032c157..c43a24d 100644
--- a/test/SILGen/objc_thunks.swift
+++ b/test/SILGen/objc_thunks.swift
@@ -445,9 +445,9 @@
 // Calling objc methods of subclass should go through native entry points
 func useHoozit(_ h: Hoozit) {
 // sil @_T011objc_thunks9useHoozityAA0D0C1h_tF
-  // In the class decl, gets dynamically dispatched
+  // In the class decl, overrides importd method, 'dynamic' was inferred
   h.fork()
-  // CHECK: class_method {{%.*}} : {{.*}}, #Hoozit.fork!1 :
+  // CHECK: class_method [volatile] {{%.*}} : {{.*}}, #Hoozit.fork!1.foreign
 
   // In an extension, 'dynamic' was inferred.
   h.foof()
diff --git a/test/SILGen/vtables.swift b/test/SILGen/vtables.swift
index 20e9b3e..dfc100b 100644
--- a/test/SILGen/vtables.swift
+++ b/test/SILGen/vtables.swift
@@ -88,11 +88,12 @@
 // Entries only exist for native Swift methods
 
 // CHECK: sil_vtable Hoozit {
-// CHECK:   #Hoozit.frob!1: {{.*}} : _T07vtables6HoozitC4frob{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.funge!1: {{.*}} : _T07vtables6HoozitC5funge{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.anse!1: {{.*}} : _T07vtables6HoozitC4anse{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.incorrige!1: {{.*}} : _T07vtables6HoozitC9incorrige{{[_0-9a-zA-Z]*}}F
-// CHECK: }
+// CHECK-NEXT:   #Hoozit.anse!1: {{.*}} : _T07vtables6HoozitC4anse{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.incorrige!1: {{.*}} : _T07vtables6HoozitC9incorrige{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> () -> Hoozit! : _T07vtables6HoozitCSQyACGycfc
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> (Int) -> Hoozit! : _T07vtables6HoozitCSQyACGSi7bellsOn_tcfc
+// CHECK-NEXT:   #Hoozit.deinit!deallocator: _T07vtables6HoozitCfD
+// CHECK-NEXT: }
 
 class Wotsit : Hoozit {
   override func funge() {}
@@ -100,11 +101,12 @@
 }
 
 // CHECK: sil_vtable Wotsit {
-// CHECK:   #Hoozit.frob!1: {{.*}} : _T07vtables6HoozitC4frob{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.funge!1: {{.*}} : _T07vtables6WotsitC5funge{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.anse!1: {{.*}} : _T07vtables6HoozitC4anse{{[_0-9a-zA-Z]*}}F
-// CHECK:   #Hoozit.incorrige!1: {{.*}} : _T07vtables6WotsitC9incorrige{{[_0-9a-zA-Z]*}}F
-// CHECK: }
+// CHECK-NEXT:   #Hoozit.anse!1: {{.*}} : _T07vtables6HoozitC4anse{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.incorrige!1: {{.*}} : _T07vtables6WotsitC9incorrige{{[_0-9a-zA-Z]*}}F
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> () -> Hoozit! : _T07vtables6WotsitCSQyACGycfc
+// CHECK-NEXT:   #Hoozit.init!initializer.1: (Hoozit.Type) -> (Int) -> Hoozit! : _T07vtables6WotsitCSQyACGSi7bellsOn_tcfc
+// CHECK-NEXT:   #Wotsit.deinit!deallocator: _T07vtables6WotsitCfD
+// CHECK-NEXT: }
 
 // <rdar://problem/15282548>
 // CHECK: sil_vtable Base {