diff --git a/include/swift/AST/Diagnostics.def b/include/swift/AST/Diagnostics.def index 532d1cb294e..1fbb3bec647 100644 --- a/include/swift/AST/Diagnostics.def +++ b/include/swift/AST/Diagnostics.def @@ -1457,6 +1457,13 @@ ERROR(invalid_sil_builtin,sil_gen,none, "INTERNAL ERROR: invalid use of builtin: %0", (StringRef)) +//============================================================================== +// SIL Analysis Diagnostics +//============================================================================== + +WARNING(missing_return,sil_analysis,none, + "missing return in the function expected to return %0", (StringRef)) + //============================================================================== // IR Generation Diagnostics //============================================================================== diff --git a/include/swift/SIL/SILLocation.h b/include/swift/SIL/SILLocation.h index e3b69a55126..a5c28d55155 100644 --- a/include/swift/SIL/SILLocation.h +++ b/include/swift/SIL/SILLocation.h @@ -14,6 +14,7 @@ #define SWIFT_SIL_LOCATION_H #include "llvm/ADT/PointerUnion.h" +#include "swift/Basic/SourceLoc.h" namespace swift { class Decl; @@ -28,7 +29,12 @@ class Stmt; /// instantiation info, etc (when we get to it). /// typedef llvm::PointerUnion3 SILLocation; - + + // FIXME: This should be refactored into a SILLocation class. +SourceLoc getSourceLocForSILLocation(SILLocation loc); +SourceLoc getStartSourceLocForSILLocation(SILLocation loc); +SourceLoc getEndSourceLocForSILLocation(SILLocation loc); + } // end swift namespace diff --git a/include/swift/SIL/SILModule.h b/include/swift/SIL/SILModule.h index 11ea2066ff0..e50dc4e25aa 100644 --- a/include/swift/SIL/SILModule.h +++ b/include/swift/SIL/SILModule.h @@ -138,8 +138,12 @@ public: return &F; return nullptr; } - - /// verify - Run the SIL verifier to make sure that all Functions follow + + /// \brief Analyze the module for correcntess and generate user diagnostics + /// if any. + void check() const; + + /// \brief Run the SIL verifier to make sure that all Functions follow /// invariants. void verify() const; diff --git a/lib/SIL/CMakeLists.txt b/lib/SIL/CMakeLists.txt index 439c86ddf27..ff681e4ac47 100644 --- a/lib/SIL/CMakeLists.txt +++ b/lib/SIL/CMakeLists.txt @@ -1,11 +1,13 @@ add_subdirectory(SILGen) add_swift_library(swiftSIL + Checker.cpp Dominance.cpp Mangle.cpp SILBasicBlock.cpp SILInstruction.cpp SILFunction.cpp SIL.cpp + SILLocation.cpp SILModule.cpp SILPrinter.cpp SILSuccessor.cpp diff --git a/lib/SIL/Checker.cpp b/lib/SIL/Checker.cpp new file mode 100644 index 00000000000..3648e944cc3 --- /dev/null +++ b/lib/SIL/Checker.cpp @@ -0,0 +1,77 @@ +//===--- Checker.cpp - Analyzes and checking of Swift SIL Code ------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +#include "swift/AST/ASTContext.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/Diagnostics.h" +#include "swift/AST/Expr.h" +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/SILLocation.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILVisitor.h" + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" + +using namespace swift; + +class BasicSILUnreachableChecker : +public SILVisitor { + ASTContext &Context; + + template + void diagnose(SourceLoc loc, Diag diag, + U &&...args) { + Context.Diags.diagnose(loc, + diag, std::forward(args)...); + } + +public: + BasicSILUnreachableChecker(ASTContext &C) : Context(C) {} + + // Base case: no extra verification to do. + void visitSILInstruction(SILInstruction *I) {} + void visitSILArgument(SILArgument *A) {} + + void visitUnreachableInst(UnreachableInst *UI) { + const SILBasicBlock *BB = UI->getParent(); + const SILFunction *F = BB->getParent(); + + // The most common case of getting an unreachable instruction is a + // missing return statement. + SILLocation FLoc = F->getLocation(); + + Type ResTy; + const Expr *E = FLoc.dyn_cast(); + assert(E && "Should be an Expr as it's the parent of the basic block."); + + if (const FuncExpr *FExpr = dyn_cast(E)) + ResTy = FExpr->getResultType(Context); + else { + // FIXME: Not all closure types have the result type getter right now. + return; + } + + // If the function does not return void, issue the diagnostic. + if (!ResTy->isVoid()) { + SILLocation L = UI->getLoc(); + if (L) + diagnose(getEndSourceLocForSILLocation(L), + diag::missing_return, ResTy.getString()); + } + } +}; + +void SILModule::check() const { + for (auto &F : *this) + BasicSILUnreachableChecker(getASTContext()) + .visitSILFunction(const_cast(&F)); +} diff --git a/lib/SIL/SILGen/SILGen.cpp b/lib/SIL/SILGen/SILGen.cpp index f30a3a32df1..a46010183a2 100644 --- a/lib/SIL/SILGen/SILGen.cpp +++ b/lib/SIL/SILGen/SILGen.cpp @@ -469,6 +469,10 @@ void SILGenModule::visitVarDecl(VarDecl *vd) { addGlobalVariable(vd); } +void SILGenModule::postEmitModule() { + M.check(); +} + //===--------------------------------------------------------------------===// // SILModule::constructSIL method implementation //===--------------------------------------------------------------------===// @@ -484,7 +488,9 @@ SILModule *SILModule::constructSIL(TranslationUnit *tu, for (auto def : tu->getASTContext().ExternalDefinitions) { sgm.emitExternalDefinition(def); } - + + sgm.postEmitModule(); + return m; } diff --git a/lib/SIL/SILGen/SILGen.h b/lib/SIL/SILGen/SILGen.h index 0254d882a51..ea3df3b396a 100644 --- a/lib/SIL/SILGen/SILGen.h +++ b/lib/SIL/SILGen/SILGen.h @@ -167,7 +167,9 @@ public: /// True if super-calling the given method from a subclass should use ObjC /// dispatch. bool requiresObjCSuperDispatch(ValueDecl *vd); - + + void postEmitModule(); + /// Known functions for bridging. SILConstant getStringToNSStringFn(); SILConstant getNSStringToStringFn(); @@ -180,20 +182,7 @@ public: U &&...args) { M.getASTContext().Diags.diagnose(loc, diag, std::forward(args)...); } - - static SourceLoc getSourceLocForSILLocation(SILLocation loc) { - if (auto decl = loc.dyn_cast()) { - return decl->getLoc(); - } - if (auto expr = loc.dyn_cast()) { - return expr->getLoc(); - } - if (auto stmt = loc.dyn_cast()) { - return stmt->getStartLoc(); - } - llvm_unreachable("impossible SILLocation"); - } - + template void diagnose(SILLocation loc, Diag diag, U &&...args) { diff --git a/lib/SIL/SILLocation.cpp b/lib/SIL/SILLocation.cpp new file mode 100644 index 00000000000..247a30af5c2 --- /dev/null +++ b/lib/SIL/SILLocation.cpp @@ -0,0 +1,57 @@ +//===--- SILLocation.cpp - Location information for SIL nodes ---*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/SIL/SILLocation.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" +#include "swift/AST/Stmt.h" + +namespace swift { +SourceLoc getSourceLocForSILLocation(SILLocation loc) { + if (auto decl = loc.dyn_cast()) { + return decl->getLoc(); + } + if (auto expr = loc.dyn_cast()) { + return expr->getLoc(); + } + if (auto stmt = loc.dyn_cast()) { + return stmt->getStartLoc(); + } + llvm_unreachable("impossible SILLocation"); +} + +SourceLoc getStartSourceLocForSILLocation(SILLocation loc) { + if (auto decl = loc.dyn_cast()) { + return decl->getStartLoc(); + } + if (auto expr = loc.dyn_cast()) { + return expr->getStartLoc(); + } + if (auto stmt = loc.dyn_cast()) { + return stmt->getStartLoc(); + } + llvm_unreachable("impossible SILLocation"); +} + +SourceLoc getEndSourceLocForSILLocation(SILLocation loc) { + if (auto decl = loc.dyn_cast()) { + return decl->getEndLoc(); + } + if (auto expr = loc.dyn_cast()) { + return expr->getEndLoc(); + } + if (auto stmt = loc.dyn_cast()) { + return stmt->getEndLoc(); + } + llvm_unreachable("impossible SILLocation"); +} +}; diff --git a/test/SIL/Diagnostics/missing_return.swift b/test/SIL/Diagnostics/missing_return.swift new file mode 100644 index 00000000000..8ef80cb1f33 --- /dev/null +++ b/test/SIL/Diagnostics/missing_return.swift @@ -0,0 +1,35 @@ +// RUN: %swift %s -verify + +func singleBlock() -> Int { + var y = 0 +} // expected-warning {{missing return in the function expected to return Int}} + +func singleBlock2() -> Int { + var y = 0 + y++ +} // expected-warning {{missing return in the function expected to return Int}} + +func multipleBlocksSingleMissing(b:Bool) -> (String, Int) { + var y = 0 + if b { + return ("a", 1) + } else if (y == 0) { + y++ + } +} // expected-warning {{missing return in the function expected to return (String, Int)}} + +func multipleBlocksAllMissing(x:Int) -> Int { + var y : Int = x + 1 + while (y > 0 ) { + --y; + break; + } + var x: Int + x++ +} // expected-warning {{missing return in the function expected to return Int}} + +// FIXME: We should not report the missing return here as this is a +// no-return function. After we fix this, we can turn the warning into error. +func MYsubscriptNonASCII(idx : Int) -> Char { + alwaysTrap() +} // expected-warning {{missing return in the function expected to return Char}}