Merge pull request #22990 from slavapestov/ctor-subclass-scope-5.0

SIL: Fix subclass scope calculation for constructors [5.0]
diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp
index 5538dba..8ae0a3d 100644
--- a/lib/SIL/SILDeclRef.cpp
+++ b/lib/SIL/SILDeclRef.cpp
@@ -892,21 +892,32 @@
   if (!hasDecl())
     return SubclassScope::NotApplicable;
 
+  auto *decl = getDecl();
+
+  if (!isa<AbstractFunctionDecl>(decl))
+    return SubclassScope::NotApplicable;
+
   // If this declaration is a function which goes into a vtable, then it's
   // symbol must be as visible as its class, because derived classes have to put
   // all less visible methods of the base class into their vtables.
 
-  if (auto *CD = dyn_cast<ConstructorDecl>(getDecl()))
-    if (!CD->isRequired())
+  if (auto *CD = dyn_cast<ConstructorDecl>(decl)) {
+    // Initializing entry points do not appear in the vtable.
+    if (kind == SILDeclRef::Kind::Initializer)
       return SubclassScope::NotApplicable;
-
-  auto *FD = dyn_cast<FuncDecl>(getDecl());
-  if (!FD)
+    // Non-required convenience inits do not apper in the vtable.
+    if (!CD->isRequired() && !CD->isDesignatedInit())
+      return SubclassScope::NotApplicable;
+  } else if (isa<DestructorDecl>(decl)) {
+    // Detructors do not appear in the vtable.
     return SubclassScope::NotApplicable;
+  } else {
+    assert(isa<FuncDecl>(decl));
+  }
 
-  DeclContext *context = FD->getDeclContext();
+  DeclContext *context = decl->getDeclContext();
 
-  // Methods from extensions don't go into vtables (yet).
+  // Methods from extensions don't go in the vtable.
   if (isa<ExtensionDecl>(context))
     return SubclassScope::NotApplicable;
 
@@ -914,25 +925,29 @@
   if (isThunk() || isForeign)
     return SubclassScope::NotApplicable;
 
-  // Default arg generators are not visible.
+  // Default arg generators don't go in the vtable.
   if (isDefaultArgGenerator())
     return SubclassScope::NotApplicable;
 
+  // Only non-final methods in non-final classes go in the vtable.
   auto *classType = context->getSelfClassDecl();
   if (!classType || classType->isFinal())
     return SubclassScope::NotApplicable;
 
-  if (FD->isFinal())
+  if (decl->isFinal())
     return SubclassScope::NotApplicable;
 
-  assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() &&
+  assert(decl->getEffectiveAccess() <= classType->getEffectiveAccess() &&
          "class must be as visible as its members");
 
   // FIXME: This is too narrow. Any class with resilient metadata should
   // probably have this, at least for method overrides that don't add new
   // vtable entries.
-  if (classType->isResilient())
+  if (classType->isResilient()) {
+    if (isa<ConstructorDecl>(decl))
+      return SubclassScope::NotApplicable;
     return SubclassScope::Resilient;
+  }
 
   switch (classType->getEffectiveAccess()) {
   case AccessLevel::Private:
diff --git a/test/IRGen/Inputs/vtable_symbol_linkage_base.swift b/test/IRGen/Inputs/vtable_symbol_linkage_base.swift
index 3ee50a6..9220883 100644
--- a/test/IRGen/Inputs/vtable_symbol_linkage_base.swift
+++ b/test/IRGen/Inputs/vtable_symbol_linkage_base.swift
@@ -11,6 +11,9 @@
   internal var internalVar: Int = 30
 }
 
+open class Middle : Base {
+  public init(x: Int) {}
+}
 
 public struct Namespace {
   open class Nested {
diff --git a/test/IRGen/vtable_symbol_linkage.swift b/test/IRGen/vtable_symbol_linkage.swift
index cb77e13..603b88c 100644
--- a/test/IRGen/vtable_symbol_linkage.swift
+++ b/test/IRGen/vtable_symbol_linkage.swift
@@ -10,8 +10,9 @@
 
 import BaseModule
 
-public class Derived : Base {
-}
+public class Derived : Base {}
+
+public class MostDerived : Middle {}
 
 public class DerivedNested : Namespace.Nested {}
 public class DerivedExtNested : Namespace.ExtNested {}