Skip to content

Commit 012ae93

Browse files
committed
SILGen: Fix SIL mandatory inlining crash that could occur with public override of an internal property
When we override a property to add a didSet, Sema also synthesizes a getter that simply delegates to the superclass property getter. The synthesized getter is marked @_transparent. This means that if the superclass getter is also transparent, but less visible than the override, mandatory inlining will crash with an assertion. To fix this, make sure SILGen does not emit a direct reference to a superclass method if the current function is marked [fragile] but the method is not. Fixes <rdar://problem/26408353>.
1 parent d36806b commit 012ae93

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,32 @@ static CanSILFunctionType getDynamicMethodLoweredType(SILGenFunction &gen,
111111
return replaceSelfTypeForDynamicLookup(ctx, methodTy, selfTy, methodName);
112112
}
113113

114+
/// Check if we can perform a dynamic dispatch on a super method call.
114115
static bool canUseStaticDispatch(SILGenFunction &gen,
115116
SILDeclRef constant) {
117+
auto *funcDecl = cast<AbstractFunctionDecl>(constant.getDecl());
118+
119+
if (funcDecl->isFinal())
120+
return true;
121+
122+
// We cannot form a direct reference to a method body defined in
123+
// Objective-C.
116124
if (constant.isForeign)
117125
return false;
118126

119-
auto *funcDecl = cast<AbstractFunctionDecl>(constant.getDecl());
127+
// If we cannot form a direct reference due to resilience constraints,
128+
// we have to dynamic dispatch.
129+
if (gen.F.isFragile() && !constant.isFragile())
130+
return false;
131+
132+
// If the method is defined in the same module, we can reference it
133+
// directly.
120134
auto thisModule = gen.SGM.M.getSwiftModule();
121-
return funcDecl->isFinal() || (thisModule == funcDecl->getModuleContext());
135+
if (thisModule == funcDecl->getModuleContext())
136+
return true;
137+
138+
// Otherwise, we must dynamic dispatch.
139+
return false;
122140
}
123141

124142
namespace {

test/SILGen/properties.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,3 +1043,27 @@ protocol ProtocolWithReadWriteSubscript {
10431043
struct CrashWithUnnamedSubscript : ProtocolWithReadWriteSubscript {
10441044
subscript(_: Int) -> Int { get { } set { } }
10451045
}
1046+
1047+
1048+
/// <rdar://problem/26408353> crash when overriding internal property with
1049+
/// public property
1050+
1051+
public class BaseClassWithInternalProperty {
1052+
var x: () = ()
1053+
}
1054+
1055+
public class DerivedClassWithPublicProperty : BaseClassWithInternalProperty {
1056+
public override var x: () {
1057+
didSet {}
1058+
}
1059+
}
1060+
1061+
// CHECK-LABEL: sil hidden [transparent] @_TFC10properties29BaseClassWithInternalPropertyg1xT_
1062+
1063+
// CHECK-LABEL: sil [transparent] [fragile] @_TFC10properties30DerivedClassWithPublicPropertyg1xT_
1064+
// CHECK: bb0([[SELF:%.*]] : $DerivedClassWithPublicProperty):
1065+
// CHECK: strong_retain [[SELF]] : $DerivedClassWithPublicProperty
1066+
// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF]] : $DerivedClassWithPublicProperty to $BaseClassWithInternalProperty
1067+
// CHECK-NEXT: [[METHOD:%.*]] = super_method [[SELF]] : $DerivedClassWithPublicProperty, #BaseClassWithInternalProperty.x!getter.1 : (BaseClassWithInternalProperty) -> () -> () , $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
1068+
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SUPER]]) : $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
1069+
// CHECK-NEXT: strong_release [[SUPER]] : $BaseClassWithInternalProperty

0 commit comments

Comments
 (0)