Skip to content

Commit 2914c6b

Browse files
committed
[di] Once we have exclusively borrowed self, if we go down the non-formal evaluation path, copy instead of asserting.
We can only do this for two reasons: 1. There is a code path that should have gone through the non-exclusively borrowed self entrypoints, but they were not implemented. 2. We are trying to access self for an argument. By copying the value, we preserve invariants around ownership and also make it easy for DI to catch 2 and not blow up in the case of 1. It is better to error in DI incorrectly, than to hit an unreachable (especially since in non-assert builds, we don't trap at unreachables and just continue to the next function in the text segment). SR-5682 rdar://35402738
1 parent 4096000 commit 2914c6b

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -834,9 +834,21 @@ RValue SILGenFunction::emitRValueForSelfInDelegationInit(SILLocation loc,
834834
}
835835

836836
// If we hit this point, we must have DidExclusiveBorrowSelf. We should have
837-
// gone through the formal evaluation variant.
838-
llvm_unreachable("Accessed self via non-formal evaluation API after "
839-
"exclusively borrowing self?!");
837+
// gone through the formal evaluation variant but did not. The only way that
838+
// this can happen is if during argument evaluation, we are accessing self in
839+
// a way that is illegal before we call super. Return a copy of self in this
840+
// case so that DI will flag on this issue. We do not care where the destroy
841+
// occurs, so we can use a normal scoped copy.
842+
ManagedValue Result;
843+
if (!SuperInitDelegationSelf) {
844+
Result = InitDelegationSelf.copy(*this, loc);
845+
} else {
846+
Result =
847+
B.createUncheckedRefCast(loc, SuperInitDelegationSelf.copy(*this, loc),
848+
InitDelegationSelf.getType());
849+
}
850+
851+
return RValue(*this, loc, refType, Result);
840852
}
841853

842854
RValue SILGenFunction::emitFormalEvaluationRValueForSelfInDelegationInit(

test/SILOptimizer/definite_init_diagnostics.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,3 +1247,65 @@ class Derived : Base {
12471247
super.init()
12481248
}
12491249
}
1250+
1251+
// This test makes sure that we properly error (but don't crash) when calling a
1252+
// subclass method as an argument to a super.init.
1253+
class MethodTestParent {
1254+
init(i: Int) {}
1255+
}
1256+
1257+
class MethodTestChild : MethodTestParent {
1258+
init() {
1259+
super.init(i: getInt()) // expected-error {{'self' used in method call 'getInt' before 'super.init' call}}
1260+
}
1261+
1262+
init(val: ()) {
1263+
// Currently we squelch the inner error of using self in method call for 'getInt2'
1264+
super.init(i: getInt2(x: self)) // expected-error {{'self' used in method call 'getInt2' before 'super.init' call}}
1265+
}
1266+
1267+
func getInt() -> Int {
1268+
return 0
1269+
}
1270+
1271+
func getInt2(x: MethodTestChild) -> Int {
1272+
return 0
1273+
}
1274+
}
1275+
1276+
// This test makes sure that if we cast self to a protocol (implicitly or not), we properly error.
1277+
protocol ProtocolCastTestProtocol : class {
1278+
}
1279+
1280+
class ProtocolCastTestParent {
1281+
init(foo f: ProtocolCastTestProtocol) {
1282+
}
1283+
1284+
init(foo2 f: Any) {
1285+
}
1286+
}
1287+
1288+
class ProtocolCastTestChild : ProtocolCastTestParent, ProtocolCastTestProtocol {
1289+
private let value: Int
1290+
1291+
init(value1 v: Int) {
1292+
value = v
1293+
super.init(foo: self) // expected-error {{'self' used before 'super.init' call}}
1294+
}
1295+
1296+
init(value2 v: Int) {
1297+
value = v
1298+
super.init(foo: self as ProtocolCastTestProtocol) // expected-error {{'self' used before 'super.init' call}}
1299+
}
1300+
1301+
init(value3 v: Int) {
1302+
value = v
1303+
super.init(foo2: self) // expected-error {{'self' used before 'super.init' call}}
1304+
}
1305+
1306+
init(value4 v: Int) {
1307+
value = v
1308+
super.init(foo2: self as Any) // expected-error {{'self' used before 'super.init' call}}
1309+
}
1310+
}
1311+

0 commit comments

Comments
 (0)