diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 35f416b43d8..9fede765c02 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -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", ()) diff --git a/lib/SILPasses/DefiniteInitialization.cpp b/lib/SILPasses/DefiniteInitialization.cpp index f8c9afc1cb7..7300c3c48cc 100644 --- a/lib/SILPasses/DefiniteInitialization.cpp +++ b/lib/SILPasses/DefiniteInitialization.cpp @@ -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. diff --git a/test/SILPasses/definite_init_failable_initializers.swift b/test/SILPasses/definite_init_failable_initializers.swift index 3e5d8903d75..c214ca7f1c2 100644 --- a/test/SILPasses/definite_init_failable_initializers.swift +++ b/test/SILPasses/definite_init_failable_initializers.swift @@ -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: ()) }