mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fix <rdar://problem/20193929> Can't "return nil" in a convenience initializer
This falls out of the rework I did of 'self' in initializers. We now correctly dealloc_ref the allocated object on the failure path of a convenience init. Swift SVN r27752
This commit is contained in:
@@ -167,9 +167,6 @@ ERROR(assignment_to_immutable_value,sil_analysis,none,
|
||||
"immutable value '%0' may not be assigned to",
|
||||
(StringRef))
|
||||
|
||||
ERROR(self_init_must_be_called_before_failure,sil_analysis,none,
|
||||
"failable convenience initializer must delegate to self.init() before "
|
||||
"returning nil", ())
|
||||
ERROR(object_not_fully_initialized_before_failure,sil_analysis,none,
|
||||
"all stored properties of a class instance must be initialized before "
|
||||
"returning nil from an initializer", ())
|
||||
|
||||
@@ -1340,8 +1340,8 @@ void LifetimeChecker::processNonTrivialRelease(unsigned ReleaseID) {
|
||||
|
||||
// Right now we don't fully support cleaning up a partially initialized object
|
||||
// after a failure. Handle this by only allowing an early 'return nil' in an
|
||||
// initializer after all properties are initialized.
|
||||
if (TheMemory.isClassInitSelf()) {
|
||||
// initializer after all properties are initialized or in a convenience init.
|
||||
if (TheMemory.isClassInitSelf() && !TheMemory.isDelegatingInit()) {
|
||||
SILLocation loc = Release->getLoc();
|
||||
|
||||
// The release is generally a cleanup in a failure block, and is usually the
|
||||
@@ -1358,25 +1358,19 @@ void LifetimeChecker::processNonTrivialRelease(unsigned ReleaseID) {
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a convenience initializer, report that self.init() must be
|
||||
// called.
|
||||
if (TheMemory.isDelegatingInit()) {
|
||||
diagnose(Module, loc, diag::self_init_must_be_called_before_failure);
|
||||
} else {
|
||||
// Otherwise all members must be initialized (including the base class, if
|
||||
// present).
|
||||
diagnose(Module, loc, diag::object_not_fully_initialized_before_failure);
|
||||
|
||||
// Note each of the members that isn't initialized.
|
||||
DIMemoryUse Use(Release, DIUseKind::Load, 0, TheMemory.NumElements);
|
||||
noteUninitializedMembers(Use);
|
||||
|
||||
// If we're tracking the state of super.init (i.e., in a derived class)
|
||||
// then report on failure to call super.init as well.
|
||||
if (TheMemory.isAnyDerivedClassSelf() &&
|
||||
Availability.get(Availability.size()-1) != DIKind::Yes)
|
||||
diagnose(Module, loc, diag::must_call_super_init_failable_init);
|
||||
}
|
||||
// All members must be initialized (including the base class, if
|
||||
// present).
|
||||
diagnose(Module, loc, diag::object_not_fully_initialized_before_failure);
|
||||
|
||||
// Note each of the members that isn't initialized.
|
||||
DIMemoryUse Use(Release, DIUseKind::Load, 0, TheMemory.NumElements);
|
||||
noteUninitializedMembers(Use);
|
||||
|
||||
// If we're tracking the state of super.init (i.e., in a derived class)
|
||||
// then report on failure to call super.init as well.
|
||||
if (TheMemory.isAnyDerivedClassSelf() &&
|
||||
Availability.get(Availability.size()-1) != DIKind::Yes)
|
||||
diagnose(Module, loc, diag::must_call_super_init_failable_init);
|
||||
}
|
||||
|
||||
// If it is all 'no' then we can handle is specially without conditional code.
|
||||
|
||||
@@ -48,7 +48,7 @@ class RootClass {
|
||||
init() { x = 0; y = 0 }
|
||||
|
||||
convenience init?(failBeforeDelegation: Bool) {
|
||||
if failBeforeDelegation { return nil } // expected-error{{failable convenience initializer must delegate to self.init() before returning nil}}
|
||||
if failBeforeDelegation { return nil } // ok
|
||||
self.init()
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class RootClass {
|
||||
}
|
||||
|
||||
convenience init?(failBeforeFailableDelegation: Bool) {
|
||||
if failBeforeFailableDelegation { return nil } // expected-error {{failable convenience initializer must delegate to self.init() before returning nil}}
|
||||
if failBeforeFailableDelegation { return nil } // ok
|
||||
|
||||
self.init(failBeforeInitialization: ())
|
||||
}
|
||||
@@ -126,8 +126,7 @@ class SubClass: RootClass {
|
||||
}
|
||||
|
||||
convenience init?(failBeforeDelegation: Bool) {
|
||||
if failBeforeDelegation { return nil }
|
||||
// expected-error@-1{{failable convenience initializer must delegate to self.init() before returning nil}}
|
||||
if failBeforeDelegation { return nil } // ok
|
||||
self.init()
|
||||
}
|
||||
|
||||
@@ -138,7 +137,6 @@ class SubClass: RootClass {
|
||||
|
||||
convenience init?(failBeforeFailableDelegation: Bool) {
|
||||
if failBeforeFailableDelegation { return nil }
|
||||
// expected-error@-1{{failable convenience initializer must delegate to self.init() before returning nil}}
|
||||
self.init(failBeforeInitialization: ())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user