Skip to content

Commit 81712c7

Browse files
committed
SIL: Don't include convenience initializers in vtables.
They're never dynamically dispatched (unless `required`), so this entry should never be used.
1 parent ae2a5cf commit 81712c7

File tree

3 files changed

+100
-5
lines changed

3 files changed

+100
-5
lines changed

include/swift/SIL/SILVTableVisitor.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,13 @@ template <class T> class SILVTableVisitor {
100100
maybeAddEntry(constant, constant.requiresNewVTableEntry());
101101
}
102102

103-
// All constructors have their initializing constructor in the
104-
// vtable, which can be used by a convenience initializer.
105-
SILDeclRef constant(cd, SILDeclRef::Kind::Initializer);
106-
maybeAddEntry(constant, constant.requiresNewVTableEntry());
103+
// Designated and/or required initializers have their initializing
104+
// constructor in the vtable, which can be used by a convenience
105+
// initializer.
106+
if (cd->isDesignatedInit() || cd->isRequired()) {
107+
SILDeclRef constant(cd, SILDeclRef::Kind::Initializer);
108+
maybeAddEntry(constant, constant.requiresNewVTableEntry());
109+
}
107110
}
108111

109112
void maybeAddEntry(SILDeclRef declRef, bool needsNewEntry) {

lib/SIL/SILDeclRef.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,15 @@ swift::getMethodDispatch(AbstractFunctionDecl *method) {
4949
return MethodDispatch::Static;
5050

5151
// Members defined directly inside a class are dynamically dispatched.
52-
if (isa<ClassDecl>(dc))
52+
if (isa<ClassDecl>(dc)) {
53+
// Convenience initializers are not dynamically dispatched unless
54+
// required.
55+
if (auto ctor = dyn_cast<ConstructorDecl>(method)) {
56+
if (!ctor->isRequired() && ctor->isConvenienceInit())
57+
return MethodDispatch::Static;
58+
}
5359
return MethodDispatch::Class;
60+
}
5461

5562
// Imported class methods are dynamically dispatched.
5663
if (method->isObjC() && method->hasClangNode())
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
class X {
4+
init() {
5+
}
6+
7+
// Convenience inits must dynamically dispatch designated inits...
8+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfC
9+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfc
10+
// CHECK: class_method %7 : $X, #X.init!initializer.1
11+
convenience init(convenience: ()) {
12+
self.init()
13+
}
14+
15+
// ...but can statically invoke peer convenience inits
16+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC17doubleConvenienceACyt_tcfC
17+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC17doubleConvenienceACyt_tcfc
18+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfc
19+
convenience init(doubleConvenience: ()) {
20+
self.init(convenience: ())
21+
}
22+
23+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC8requiredACyt_tcfC
24+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC8requiredACyt_tcfc
25+
required init(required: ()) {
26+
}
27+
28+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC19requiredConvenienceACyt_tcfC
29+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC19requiredConvenienceACyt_tcfc
30+
required convenience init(requiredConvenience: ()) {
31+
self.init(required: ())
32+
}
33+
34+
// Convenience inits must dynamically dispatch required peer convenience inits
35+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC25requiredDoubleConvenienceACyt_tcfC
36+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation1XC25requiredDoubleConvenienceACyt_tcfc
37+
// CHECK: class_method %7 : $X, #X.init!initializer.1
38+
required convenience init(requiredDoubleConvenience: ()) {
39+
self.init(requiredDoubleConvenience: ())
40+
}
41+
}
42+
43+
// CHECK-LABEL: sil hidden @$S32convenience_init_peer_delegation11invocations2xtyAA1XCm_tF
44+
func invocations(xt: X.Type) {
45+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XCACycfC
46+
_ = X()
47+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfC
48+
_ = X(convenience: ())
49+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC17doubleConvenienceACyt_tcfC
50+
_ = X(doubleConvenience: ())
51+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC8requiredACyt_tcfC
52+
_ = X(required: ())
53+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC19requiredConvenienceACyt_tcfC
54+
_ = X(requiredConvenience: ())
55+
// CHECK: function_ref @$S32convenience_init_peer_delegation1XC25requiredDoubleConvenienceACyt_tcfC
56+
_ = X(requiredDoubleConvenience: ())
57+
58+
// CHECK: class_method %0 : $@thick X.Type, #X.init!allocator.1
59+
_ = xt.init(required: ())
60+
// CHECK: class_method %0 : $@thick X.Type, #X.init!allocator.1
61+
_ = xt.init(requiredConvenience: ())
62+
// CHECK: class_method %0 : $@thick X.Type, #X.init!allocator.1
63+
_ = xt.init(requiredDoubleConvenience: ())
64+
}
65+
66+
// CHECK-LABEL: sil_vtable X
67+
// -- designated init()
68+
// CHECK-NOT: @$S32convenience_init_peer_delegation1XCACycfC
69+
// CHECK: @$S32convenience_init_peer_delegation1XCACycfc
70+
71+
// -- no unrequired convenience inits
72+
// CHECK-NOT: @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfC
73+
// CHECK-NOT: @$S32convenience_init_peer_delegation1XC0A0ACyt_tcfc
74+
// CHECK-NOT: @$S32convenience_init_peer_delegation1XC17doubleConvenienceACyt_tcfC
75+
// CHECK-NOT: @$S32convenience_init_peer_delegation1XC17doubleConvenienceACyt_tcfc
76+
77+
// -- designated init(required:)
78+
// CHECK: @$S32convenience_init_peer_delegation1XC8requiredACyt_tcfC
79+
// CHECK: @$S32convenience_init_peer_delegation1XC8requiredACyt_tcfc
80+
// -- convenience init(requiredConvenience:)
81+
// CHECK: @$S32convenience_init_peer_delegation1XC19requiredConvenienceACyt_tcfC
82+
// CHECK: @$S32convenience_init_peer_delegation1XC19requiredConvenienceACyt_tcfc
83+
// -- convenience init(requiredDoubleConvenience:)
84+
// CHECK: @$S32convenience_init_peer_delegation1XC25requiredDoubleConvenienceACyt_tcfC
85+
// CHECK: @$S32convenience_init_peer_delegation1XC25requiredDoubleConvenienceACyt_tcfc

0 commit comments

Comments
 (0)