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:
Chris Lattner
2015-04-26 05:13:48 +00:00
parent abb34fa1b0
commit 61afbe993f
3 changed files with 18 additions and 29 deletions

View File

@@ -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.