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 {}