diff --git a/clang/Analysis/LiveVariables.cpp b/clang/Analysis/LiveVariables.cpp index 629065190223aa95b52ce558967cfaa29c8a2749..b5248fe99e34940a83604100b4cc895753198522 100644 --- a/clang/Analysis/LiveVariables.cpp +++ b/clang/Analysis/LiveVariables.cpp @@ -372,7 +372,7 @@ void LiveVariables::runOnBlock(const CFGBlock* B, LiveVariablesAuditor* Auditor) // liveness queries // -bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const { +bool LiveVariables::isLive(const CFGBlock* B, const Decl* D) const { BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B); assert (I != LiveAtBlockEntryMap.end()); @@ -382,6 +382,12 @@ bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const { return I->second[VI->second.Idx]; } +bool LiveVariables::isLive(llvm::BitVector& Live, const Decl* D) const { + VarInfoMap::const_iterator VI = VarInfos.find(D); + assert (VI != VarInfos.end()); + return Live[VI->second.Idx]; +} + bool LiveVariables::KillsVar(const Stmt* S, const Decl* D) const { VarInfoMap::const_iterator VI = VarInfos.find(D); assert (VI != VarInfos.end()); @@ -404,6 +410,15 @@ const LiveVariables::VarInfo& LiveVariables::getVarInfo(const Decl* D) const { return const_cast(this)->getVarInfo(D); } +//===----------------------------------------------------------------------===// +// Defaults for LiveVariablesAuditor + +void LiveVariablesAuditor::AuditStmt(Stmt* S, LiveVariables& L, + llvm::BitVector& V) {} + +void LiveVariablesAuditor::AuditBlockExit(const CFGBlock* B, LiveVariables& L, + llvm::BitVector& V) {} + //===----------------------------------------------------------------------===// // printing liveness state for debugging // diff --git a/clang/Driver/ASTStreamers.cpp b/clang/Driver/ASTStreamers.cpp index b5ea29328e228cf6bd610676d390f8f54de70304..95d39fa35287f2b06be8066e90c76a59a5c4fd28 100644 --- a/clang/Driver/ASTStreamers.cpp +++ b/clang/Driver/ASTStreamers.cpp @@ -15,6 +15,7 @@ #include "clang/AST/AST.h" #include "clang/AST/CFG.h" #include "clang/Analysis/LiveVariables.h" +#include "clang/Analysis/LocalCheckers.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ASTStreamer.h" using namespace clang; @@ -209,4 +210,30 @@ void clang::AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID) ASTStreamer_Terminate(Streamer); } +void clang::RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID,bool Stats) +{ + ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable()); + ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID); + + while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) { + if (FunctionDecl *FD = dyn_cast(D)) { + if (FD->getBody()) { + if (CFG* C = CFG::buildCFG(FD->getBody())) { + clang::CheckDeadStores(*C,PP); + } + else + fprintf(stderr," Error processing CFG.\n"); + } + } + } + + if (Stats) { + fprintf(stderr, "\nSTATISTICS:\n"); + ASTStreamer_PrintStats(Streamer); + Context.PrintStats(); + } + + ASTStreamer_Terminate(Streamer); +} + diff --git a/clang/Driver/ASTStreamers.h b/clang/Driver/ASTStreamers.h index 34ce8647b0e1a41a8933fe5e7c88b36a2d6aa823..f568e8e866e10108faf51150cda2dedc2f32e62d 100644 --- a/clang/Driver/ASTStreamers.h +++ b/clang/Driver/ASTStreamers.h @@ -29,6 +29,8 @@ void DumpCFGs(Preprocessor &PP, unsigned MainFileID, void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID); +void RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID, bool Stats); + } // end clang namespace #endif diff --git a/clang/Driver/Makefile b/clang/Driver/Makefile index eca316e2042cd7f24ea919e7a52bd13fae3dfe3b..3577a2bca14d0765e9e4afdc68e680b513abcef7 100644 --- a/clang/Driver/Makefile +++ b/clang/Driver/Makefile @@ -3,6 +3,6 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../include CXXFLAGS = -fno-rtti TOOLNAME = clang -USEDLIBS = clangCodeGen.a clangSEMA.a clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a +USEDLIBS = clangCodeGen.a clangAnalysis.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a include $(LEVEL)/Makefile.common diff --git a/clang/Driver/clang.cpp b/clang/Driver/clang.cpp index ed540aed06e93522968c8f2ba0f6cf66780769cb..79a09f17611c1d7ca91db0106f7a7a3fdcf417b0 100644 --- a/clang/Driver/clang.cpp +++ b/clang/Driver/clang.cpp @@ -53,8 +53,9 @@ enum ProgActions { ParseASTCheck, // Parse ASTs and check diagnostics. ParseAST, // Parse ASTs. ParseCFGDump, // Parse ASTS. Build CFGs. Print CFGs. - ParseCFGView, // Parse ASTS. Build CFGs. View CFGs (Graphviz). + ParseCFGView, // Parse ASTS. Build CFGs. View CFGs. AnalysisLiveVariables, // Print results of live-variable analysis. + WarnDeadStores, // Run DeadStores checker on parsed ASTs. ParsePrintCallbacks, // Parse and print each callback. ParseSyntaxOnly, // Parse and perform semantic analysis. ParseNoop, // Parse with noop callbacks. @@ -93,6 +94,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, "Run parser, then build and view CFGs with Graphviz."), clEnumValN(AnalysisLiveVariables, "dump-live-variables", "Print results of live variable analysis."), + clEnumValN(WarnDeadStores, "check-dead-stores", + "Flag warnings of stores to dead variables."), clEnumValN(EmitLLVM, "emit-llvm", "Build ASTs then convert to LLVM, emit .ll file"), clEnumValEnd)); @@ -851,7 +854,10 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID, break; case AnalysisLiveVariables: AnalyzeLiveVariables(PP, MainFileID); - break; + break; + case WarnDeadStores: + RunDeadStoresCheck(PP, MainFileID, Stats); + break; case EmitLLVM: EmitLLVMFromASTs(PP, MainFileID, Stats); break; diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index 21ec8d128e85683469aa0c4d9c565c4eae6588c9..0ca23958c7d4da21dd41f84d48841bdb04ff2f4c 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; }; + 355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */; }; 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; }; 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; }; 84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; }; @@ -210,6 +211,8 @@ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = ""; }; 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = ""; }; 3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = ""; }; + 355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = ""; }; + 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = Analysis/DeadStores.cpp; sourceTree = ""; }; 356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = ""; }; 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = ""; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = ""; }; @@ -377,9 +380,18 @@ name = Products; sourceTree = ""; }; + 355CF6850C90A8D600A08AA3 /* LocalCheckers */ = { + isa = PBXGroup; + children = ( + 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */, + ); + name = LocalCheckers; + sourceTree = ""; + }; 356EF9AF0C8F7DA4006650F5 /* Analysis */ = { isa = PBXGroup; children = ( + 355CF6820C90A8B600A08AA3 /* LocalCheckers.h */, 356EF9B20C8F7DBA006650F5 /* LiveVariables.h */, ); name = Analysis; @@ -389,6 +401,7 @@ isa = PBXGroup; children = ( 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */, + 355CF6850C90A8D600A08AA3 /* LocalCheckers */, ); name = Analysis; sourceTree = ""; @@ -741,6 +754,7 @@ 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */, DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */, 356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */, + 355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/clang/include/clang/Analysis/LiveVariables.h b/clang/include/clang/Analysis/LiveVariables.h index 4f1e5c595a752582d5e9ca7c50fa3f9a977e2c26..c63dc7c0d248a13c9bc0397b0ffe083ab5573fbf 100644 --- a/clang/include/clang/Analysis/LiveVariables.h +++ b/clang/include/clang/Analysis/LiveVariables.h @@ -30,14 +30,14 @@ namespace clang { class LiveVariablesAuditor { public: - virtual ~LiveVariablesAuditor(); + virtual ~LiveVariablesAuditor() {} /// AuditStmt - A callback invoked right before invoking the liveness /// transfer function on the given statement. If the liveness information /// has been previously calculated by running LiveVariables::runOnCFG, /// then V contains the liveness information after the execution of /// the given statement. - virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V) = 0; + virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V); /// AuditBlockExit - A callback invoked right before invoking the liveness /// transfer function on the given block. If the liveness information @@ -45,7 +45,7 @@ public: /// then V contains the liveness information after the execution of /// the given block. virtual void AuditBlockExit(const CFGBlock* B, LiveVariables& L, - llvm::BitVector& V) = 0; + llvm::BitVector& V); }; class LiveVariables { @@ -100,7 +100,12 @@ public: /// IsLive - Return true if a variable is live at beginning of a specified // block. - bool IsLive(const CFGBlock* B, const Decl* D) const; + bool isLive(const CFGBlock* B, const Decl* D) const; + + /// IsLive - Return true if a variable is live according to the provided + /// livness bitvector. This is typically used by classes that subclass + /// LiveVariablesAuditor. + bool isLive(llvm::BitVector& V, const Decl* D) const; /// getVarInfo - Return the liveness information associated with a given /// variable. diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 5009fa724eed48cacd2062ea20a19f60bd9c462b..a3249d742b0ccabc98489e2df72718ae1ca9e2a6 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -748,6 +748,9 @@ DIAG(warn_ret_stack_ref, WARNING, DIAG(warn_floatingpoint_eq, WARNING, "comparing floating point with == or != is unsafe") +// CHECK: stores to variables that are no longer live (dead stores) +DIAG(warn_dead_store, WARNING, "value stored to variable is never used") + // CFString checking DIAG(err_cfstring_literal_not_string_constant, ERROR, "CFString literal is not a string constant")