Skip to content

DI: self-consumed analysis rework, volume 1 #12445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 32 additions & 44 deletions lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,8 @@ namespace {

private:

void emitSelfConsumedDiagnostic(SILInstruction *Inst);

LiveOutBlockState &getBlockInfo(SILBasicBlock *BB) {
return PerBlockInfo.insert({BB,
LiveOutBlockState(TheMemory.NumElements)}).first->second;
Expand Down Expand Up @@ -920,18 +922,23 @@ void LifetimeChecker::handleLoadUse(unsigned UseID) {
}
}

void LifetimeChecker::emitSelfConsumedDiagnostic(SILInstruction *Inst) {
if (!shouldEmitError(Inst))
return;

diagnose(Module, Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
}

void LifetimeChecker::handleStoreUse(unsigned UseID) {
DIMemoryUse &InstInfo = Uses[UseID];

if (getSelfConsumedAtInst(InstInfo.Inst) != DIKind::No) {
// FIXME: more specific diagnostics here, handle this case gracefully below.
if (!shouldEmitError(InstInfo.Inst))
if (TheMemory.isAnyInitSelf()) {
if (getSelfConsumedAtInst(InstInfo.Inst) != DIKind::No) {
emitSelfConsumedDiagnostic(InstInfo.Inst);
return;

diagnose(Module, InstInfo.Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
return;
}
}

// Determine the liveness state of the element that we care about.
Expand Down Expand Up @@ -1025,13 +1032,7 @@ void LifetimeChecker::handleInOutUse(const DIMemoryUse &Use) {
// before the "address" is passed as an l-value.
if (!isInitializedAtUse(Use, &IsSuperInitDone, &FailedSelfUse)) {
if (FailedSelfUse) {
// FIXME: more specific diagnostics here, handle this case gracefully below.
if (!shouldEmitError(Use.Inst))
return;

diagnose(Module, Use.Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
emitSelfConsumedDiagnostic(Use.Inst);
return;
}

Expand Down Expand Up @@ -1133,13 +1134,7 @@ void LifetimeChecker::handleEscapeUse(const DIMemoryUse &Use) {
auto Inst = Use.Inst;

if (FailedSelfUse) {
// FIXME: more specific diagnostics here, handle this case gracefully below.
if (!shouldEmitError(Inst))
return;

diagnose(Module, Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
emitSelfConsumedDiagnostic(Inst);
return;
}

Expand Down Expand Up @@ -1500,13 +1495,7 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
SILInstruction *Inst = Use.Inst;

if (FailedSelfUse) {
// FIXME: more specific diagnostics here, handle this case gracefully below.
if (!shouldEmitError(Inst))
return;

diagnose(Module, Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
emitSelfConsumedDiagnostic(Inst);
return;
}

Expand Down Expand Up @@ -1664,16 +1653,11 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
void LifetimeChecker::handleSelfInitUse(DIMemoryUse &InstInfo) {
auto *Inst = InstInfo.Inst;

assert(TheMemory.isAnyInitSelf());
assert(TheMemory.getType()->hasReferenceSemantics());

if (getSelfConsumedAtInst(Inst) != DIKind::No) {
// FIXME: more specific diagnostics here, handle this case gracefully below.
if (!shouldEmitError(Inst))
return;

diagnose(Module, Inst->getLoc(),
diag::self_inside_catch_superselfinit,
(unsigned)TheMemory.isDelegatingInit());
emitSelfConsumedDiagnostic(Inst);
return;
}

Expand Down Expand Up @@ -1899,8 +1883,10 @@ void LifetimeChecker::processNonTrivialRelease(unsigned ReleaseID) {
isa<DestroyAddrInst>(Release));

auto Availability = getLivenessAtInst(Release, 0, TheMemory.NumElements);
DIKind SelfConsumed =
getSelfConsumedAtInst(Release);
DIKind SelfConsumed = DIKind::No;

if (TheMemory.isAnyInitSelf())
SelfConsumed = getSelfConsumedAtInst(Release);

if (SelfConsumed == DIKind::Yes) {
// We're in an error path after performing a self.init or super.init
Expand Down Expand Up @@ -2643,12 +2629,14 @@ bool LifetimeChecker::isInitializedAtUse(const DIMemoryUse &Use,
bool *FailedSelfUse) {
if (FailedSelfUse) *FailedSelfUse = false;
if (SuperInitDone) *SuperInitDone = true;

// If the self.init() or super.init() call threw an error and
// we caught it, self is no longer available.
if (getSelfConsumedAtInst(Use.Inst) != DIKind::No) {
if (FailedSelfUse) *FailedSelfUse = true;
return false;

if (TheMemory.isAnyInitSelf()) {
// If the self.init() or super.init() call threw an error and
// we caught it, self is no longer available.
if (getSelfConsumedAtInst(Use.Inst) != DIKind::No) {
if (FailedSelfUse) *FailedSelfUse = true;
return false;
}
}

// Determine the liveness states of the elements that we care about.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,61 @@ class ErrantClass : ErrantBaseClass {
} catch {}
} // expected-error {{'self' used inside 'catch' block reachable from super.init call}}

init(invalidEscapeDesignated2: ()) throws {
x = 10
y = 10
do {
try super.init()
} catch {
try super.init() // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
}
} // expected-error {{'self' used inside 'catch' block reachable from super.init call}}

init(invalidEscapeDesignated3: ()) {
x = 10
y = 10
do {
try super.init()
} catch {
print(self.x) // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
self.y = 20 // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
}
} // expected-error {{'self' used inside 'catch' block reachable from super.init call}}

init(invalidEscapeDesignated4: ()) throws {
x = 10
y = 10
do {
try super.init()
} catch let e {
print(self.x) // expected-error {{'self' used inside 'catch' block reachable from super.init call}}
throw e
}
}

convenience init(invalidEscapeConvenience: ()) {
do {
try self.init()
} catch {}
} // expected-error {{'self' used inside 'catch' block reachable from self.init call}}

convenience init(invalidEscapeConvenience2: ()) throws {
do {
try self.init()
} catch {
try self.init() // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
}
} // expected-error {{'self' used inside 'catch' block reachable from self.init call}}

convenience init(invalidEscapeConvenience3: ()) throws {
do {
try self.init()
} catch let e {
print(self) // expected-error {{'self' used inside 'catch' block reachable from self.init call}}
throw e
}
}

init(noEscapeDesignated: ()) throws {
x = 10
y = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ bb0(%0 : @owned $DerivedClassWithIVars):
%14 = function_ref @superinit : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars
%15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars // expected-error {{property 'self.a' not initialized at super.init call}}
%16 = unchecked_ref_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars
assign %16 to %3 : $*DerivedClassWithIVars
store %16 to [init] %3 : $*DerivedClassWithIVars

%18 = load [copy] %3 : $*DerivedClassWithIVars
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <DerivedClassWithIVars>
Expand Down Expand Up @@ -272,7 +272,7 @@ bb0(%0 : @owned $DerivedClassWithIVars, %i : @trivial $Int):
// Call super.init.
%15 = apply %14(%13) : $@convention(method) (@owned RootClassWithIVars) -> @owned RootClassWithIVars
%16 = unchecked_ref_cast %15 : $RootClassWithIVars to $DerivedClassWithIVars
assign %16 to %3 : $*DerivedClassWithIVars
store %16 to [init] %3 : $*DerivedClassWithIVars
%18 = load [copy] %3 : $*DerivedClassWithIVars
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <DerivedClassWithIVars>
return %18 : $DerivedClassWithIVars
Expand Down