Skip to content

Fix various bogus unreachable code warnings #15567

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 5 commits into from
Jun 6, 2018
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
2 changes: 1 addition & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3981,7 +3981,7 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
getRepresentation() == SILFunctionTypeRepresentation::Thick;
}

bool isNoReturnFunction(); // Defined in SILType.cpp
bool isNoReturnFunction() const; // Defined in SILType.cpp

class ABICompatibilityCheckResult {
friend class SILFunctionType;
Expand Down
10 changes: 8 additions & 2 deletions lib/SIL/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,14 @@ bool SILModuleConventions::isPassedIndirectlyInSIL(SILType type, SILModule &M) {
return false;
}

bool SILFunctionType::isNoReturnFunction() {
return getDirectFormalResultsType().getASTType()->isUninhabited();

bool SILFunctionType::isNoReturnFunction() const {
for (unsigned i = 0, e = getNumResults(); i < e; ++i) {
if (getResults()[i].getType()->isUninhabited())
return true;
}

return false;
}

#ifndef NDEBUG
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4272,6 +4272,9 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
// Pop the argument scope.
argScope.pop();

if (substFnType->isNoReturnFunction())
loc.markAutoGenerated();

// Explode the direct results.
SILFunctionConventions substFnConv(substFnType, SGM.M);
SmallVector<ManagedValue, 4> directResults;
Expand Down
4 changes: 4 additions & 0 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ namespace {
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
loc.markAutoGenerated();

assert(base.isLValue());
SGF.B.createEndAccess(loc, base.getValue(), /*abort*/ false);
}
Expand Down Expand Up @@ -1566,6 +1568,8 @@ namespace {
ManagedValue base,
MaterializedLValue materialized,
bool isFinal) override {
loc.markAutoGenerated();

// If this is final, we can consume the owner (stored as
// 'base'). If it isn't, we actually need to retain it, because
// we've still got a release active.
Expand Down
9 changes: 7 additions & 2 deletions lib/SILGen/SILGenPoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3415,7 +3415,12 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy,
F.setBare(IsBare);

SILLocation loc(witness.getDecl());
FullExpr scope(Cleanups, CleanupLocation::get(loc));
loc.markAutoGenerated();

CleanupLocation cleanupLoc(witness.getDecl());
cleanupLoc.markAutoGenerated();

FullExpr scope(Cleanups, cleanupLoc);
FormalEvaluationScope formalEvalScope(*this);

auto witnessKind = getWitnessDispatchKind(witness);
Expand Down Expand Up @@ -3491,7 +3496,7 @@ void SILGenFunction::emitProtocolWitness(AbstractionPattern reqtOrigTy,
SILValue reqtResultValue = resultPlanner.execute(witnessResultValue);

scope.pop();
B.createReturn(CleanupLocation::get(loc), reqtResultValue);
B.createReturn(loc, reqtResultValue);
}

//===----------------------------------------------------------------------===//
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,9 @@ void StmtEmitter::visitReturnStmt(ReturnStmt *S) {
if (!S->hasResult())
// Void return.
SGF.Cleanups.emitBranchAndCleanups(SGF.ReturnDest, Loc);
else if (S->getResult()->getType()->isUninhabited())
// Never return.
SGF.emitIgnoredExpr(S->getResult());
else
SGF.emitReturnExpr(Loc, S->getResult());
}
Expand Down
14 changes: 14 additions & 0 deletions lib/SILOptimizer/Mandatory/DiagnoseUnreachable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,20 @@ static SILInstruction *getAsCallToNoReturn(SILInstruction *I) {
if (BI->getModule().isNoReturnBuiltinOrIntrinsic(BI->getName()))
return BI;
}

// These appear in accessors for stored properties with uninhabited
// type. Since a type containing an uninhabited stored property is
// itself uninhabited, we treat these identically to fatalError(), etc.
if (auto *SEI = dyn_cast<StructExtractInst>(I)) {
if (SEI->getType().getASTType()->isUninhabited())
return SEI;
}

if (auto *SEAI = dyn_cast<StructElementAddrInst>(I)) {
if (SEAI->getType().getASTType()->isUninhabited())
return SEAI;
}

return nullptr;
}

Expand Down
4 changes: 1 addition & 3 deletions test/SILOptimizer/specialize.sil
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,7 @@ bb0:
%6 = function_ref @action_thunk : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error)
%7 = partial_apply %6(%5) : $@convention(thin) (@owned @callee_owned () -> (Never, @error Error)) -> (@out Never, @error Error)
%8 = apply [nothrow] %1<Never>(%2, %7) : $@convention(thin) <τ_0_0> (@owned @callee_owned () -> (@out τ_0_0, @error Error)) -> (@out τ_0_0, @error Error)
dealloc_stack %2 : $*Never
%12 = tuple ()
return %12 : $()
unreachable
} // end sil function 'testGenericClosureSpecialization'

// Test a specialization of a self-recursive generic closure.
Expand Down
58 changes: 58 additions & 0 deletions test/SILOptimizer/unreachable_code.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,23 +330,81 @@ class FailingClass {
// We should not report unreachable code inside protocol witness thunks

protocol Fooable {
init()
func foo() -> Never
}
struct Foo: Fooable {
init() { // no-warning
fatalError()
}

func foo() -> Never { // no-warning
while true {}
}
}

// We should not report unreachable code inside vtable thunks
class Base {
required init(x: Int) {
fatalError()
}

func foo(x: Int) -> Never {
while true {}
}
}

class Derived : Base {
required init(x: Int?) {
fatalError()
}

override func foo(x: Int?) -> Never {
while true {}
}
}

// Inout writeback
func takesInOut(value: inout SillyStruct) -> Never {
while true {}
}

struct SillyStruct {
mutating func mutatingMethod() -> Never {
takesInOut(value: &self)
}
}

// This triggers various problems
public func genericMightBeNever<R>(
_ body: () -> R) -> R {
while true {}

}

func sillyGenericExample() -> Never {
return genericMightBeNever {
return genericMightBeNever {
return fatalError()
}
}
}

// https://bugs.swift.org/browse/SR-7472

protocol P {
static var theThing: Self { get }
}

extension Never : P {
static var theThing: Never { return fatalError() }
}

func test<T: P>(_ type: T.Type) -> T {
return type.theThing
}

func f(i: Int?) {
guard i != nil else { Never.theThing }
guard i != nil else { test(Never.self) }
}