diff options
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/AnalysisContext.cpp | 12 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 33 | ||||
-rw-r--r-- | lib/Analysis/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Analysis/LiveVariables.cpp | 21 | ||||
-rw-r--r-- | lib/Analysis/PrintfFormatString.cpp | 224 | ||||
-rw-r--r-- | lib/Analysis/ReachableCode.cpp | 278 | ||||
-rw-r--r-- | lib/Analysis/UninitializedValues.cpp | 8 |
7 files changed, 513 insertions, 64 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index ccd5088f2ec75..d9933e85cb910 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -186,6 +186,18 @@ LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const { return NULL; } +bool LocationContext::isParentOf(const LocationContext *LC) const { + do { + const LocationContext *Parent = LC->getParent(); + if (Parent == this) + return true; + else + LC = Parent; + } while (LC); + + return false; +} + //===----------------------------------------------------------------------===// // Lazily generated map to query the external variables referenced by a Block. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 5b8aeae5d1c50..a4a021f20b21c 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -38,11 +38,16 @@ static SourceLocation GetEndLoc(Decl* D) { class AddStmtChoice { public: - enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue }; -public: - AddStmtChoice(Kind kind) : k(kind) {} - bool alwaysAdd() const { return k != NotAlwaysAdd; } - bool asLValue() const { return k == AlwaysAddAsLValue; } + enum Kind { NotAlwaysAdd = 0, + AlwaysAdd = 1, + AsLValueNotAlwaysAdd = 2, + AlwaysAddAsLValue = 3 }; + + AddStmtChoice(Kind kind) : k(kind) {} + + bool alwaysAdd() const { return (unsigned)k & 0x1; } + bool asLValue() const { return k >= AlwaysAddAsLValue; } + private: Kind k; }; @@ -589,7 +594,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { AddEHEdge = false; if (!NoReturn && !AddEHEdge) - return VisitStmt(C, asc); + return VisitStmt(C, AddStmtChoice::AlwaysAdd); if (Block) { Succ = Block; @@ -771,18 +776,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) { Expr *Init = VD->getInit(); if (Init) { - // Optimization: Don't create separate block-level statements for literals. - switch (Init->getStmtClass()) { - case Stmt::IntegerLiteralClass: - case Stmt::CharacterLiteralClass: - case Stmt::StringLiteralClass: - break; - default: - Block = addStmt(Init, - VD->getType()->isReferenceType() - ? AddStmtChoice::AlwaysAddAsLValue - : AddStmtChoice::AlwaysAdd); - } + AddStmtChoice::Kind k = + VD->getType()->isReferenceType() ? AddStmtChoice::AsLValueNotAlwaysAdd + : AddStmtChoice::NotAlwaysAdd; + Visit(Init, AddStmtChoice(k)); } // If the type of VD is a VLA, then we must process its size expressions. diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 4f8259e449392..b4e0e242485b1 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangAnalysis CFG.cpp LiveVariables.cpp PrintfFormatString.cpp + ReachableCode.cpp UninitializedValues.cpp ) diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 94ed75286dee2..01a36a1074e8f 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -86,6 +86,12 @@ LiveVariables::LiveVariables(AnalysisContext &AC) { RegisterDecls R(getAnalysisData()); cfg.VisitBlockStmts(R); + + // Register all parameters even if they didn't occur in the function body. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(AC.getDecl())) + for (FunctionDecl::param_const_iterator PI = FD->param_begin(), + PE = FD->param_end(); PI != PE; ++PI) + getAnalysisData().Register(*PI); } //===----------------------------------------------------------------------===// @@ -274,9 +280,16 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE = DS->decl_end(); DI != DE; ++DI) if (VarDecl* VD = dyn_cast<VarDecl>(*DI)) { - // The initializer is evaluated after the variable comes into scope. + // Update liveness information by killing the VarDecl. + unsigned bit = AD.getIdx(VD); + LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); + + // The initializer is evaluated after the variable comes into scope, but + // before the DeclStmt (which binds the value to the variable). // Since this is a reverse dataflow analysis, we must evaluate the - // transfer function for this expression first. + // transfer function for this expression after the DeclStmt. If the + // initializer references the variable (which is bad) then we extend + // its liveness. if (Expr* Init = VD->getInit()) Visit(Init); @@ -286,10 +299,6 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { StmtIterator E; for (; I != E; ++I) Visit(*I); } - - // Update liveness information by killing the VarDecl. - unsigned bit = AD.getIdx(VD); - LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); } } diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 55abd10771506..46acc8a377bf1 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -15,10 +15,12 @@ #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" -using clang::analyze_printf::FormatSpecifier; -using clang::analyze_printf::OptionalAmount; using clang::analyze_printf::ArgTypeResult; +using clang::analyze_printf::FormatSpecifier; using clang::analyze_printf::FormatStringHandler; +using clang::analyze_printf::OptionalAmount; +using clang::analyze_printf::PositionContext; + using namespace clang; namespace { @@ -66,24 +68,19 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) { const char *I = Beg; UpdateOnReturn <const char*> UpdateBeg(Beg, I); - bool foundDigits = false; unsigned accumulator = 0; + bool hasDigits = false; for ( ; I != E; ++I) { char c = *I; if (c >= '0' && c <= '9') { - foundDigits = true; + hasDigits = true; accumulator += (accumulator * 10) + (c - '0'); continue; } - if (foundDigits) - return OptionalAmount(accumulator, Beg); - - if (c == '*') { - ++I; - return OptionalAmount(OptionalAmount::Arg, Beg); - } + if (hasDigits) + return OptionalAmount(OptionalAmount::Constant, accumulator, Beg); break; } @@ -91,9 +88,129 @@ static OptionalAmount ParseAmount(const char *&Beg, const char *E) { return OptionalAmount(); } +static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, + unsigned &argIndex) { + if (*Beg == '*') { + ++Beg; + return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg); + } + + return ParseAmount(Beg, E); +} + +static OptionalAmount ParsePositionAmount(FormatStringHandler &H, + const char *Start, + const char *&Beg, const char *E, + PositionContext p) { + if (*Beg == '*') { + const char *I = Beg + 1; + const OptionalAmount &Amt = ParseAmount(I, E); + + if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { + H.HandleInvalidPosition(Beg, I - Beg, p); + return OptionalAmount(false); + } + + if (I== E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return OptionalAmount(false); + } + + assert(Amt.getHowSpecified() == OptionalAmount::Constant); + + if (*I == '$') { + // Special case: '*0$', since this is an easy mistake. + if (Amt.getConstantAmount() == 0) { + H.HandleZeroPosition(Beg, I - Beg + 1); + return OptionalAmount(false); + } + + const char *Tmp = Beg; + Beg = ++I; + + return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, + Tmp); + } + + H.HandleInvalidPosition(Beg, I - Beg, p); + return OptionalAmount(false); + } + + return ParseAmount(Beg, E); +} + +static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS, + const char *Start, const char *&Beg, const char *E, + unsigned *argIndex) { + if (argIndex) { + FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); + } + else { + const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, + analyze_printf::PrecisionPos); + if (Amt.isInvalid()) + return true; + FS.setPrecision(Amt); + } + return false; +} + +static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS, + const char *Start, const char *&Beg, const char *E, + unsigned *argIndex) { + // FIXME: Support negative field widths. + if (argIndex) { + FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); + } + else { + const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, + analyze_printf::FieldWidthPos); + if (Amt.isInvalid()) + return true; + FS.setFieldWidth(Amt); + } + return false; +} + + +static bool ParseArgPosition(FormatStringHandler &H, + FormatSpecifier &FS, const char *Start, + const char *&Beg, const char *E) { + + using namespace clang::analyze_printf; + const char *I = Beg; + + const OptionalAmount &Amt = ParseAmount(I, E); + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } + + if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { + // Special case: '%0$', since this is an easy mistake. + if (Amt.getConstantAmount() == 0) { + H.HandleZeroPosition(Start, I - Start); + return true; + } + + FS.setArgIndex(Amt.getConstantAmount() - 1); + FS.setUsesPositionalArg(); + // Update the caller's pointer if we decided to consume + // these characters. + Beg = I; + return false; + } + + return false; +} + static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, const char *&Beg, - const char *E) { + const char *E, + unsigned &argIndex) { using namespace clang::analyze_printf; @@ -126,6 +243,14 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, } FormatSpecifier FS; + if (ParseArgPosition(H, FS, Start, I, E)) + return true; + + if (I == E) { + // No more characters left? + H.HandleIncompleteFormatSpecifier(Start, E - Start); + return true; + } // Look for flags (if any). bool hasMore = true; @@ -149,7 +274,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, } // Look for the field width (if any). - FS.setFieldWidth(ParseAmount(I, E)); + if (ParseFieldWidth(H, FS, Start, I, E, + FS.usesPositionalArg() ? 0 : &argIndex)) + return true; if (I == E) { // No more characters left? @@ -165,7 +292,9 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, return true; } - FS.setPrecision(ParseAmount(I, E)); + if (ParsePrecision(H, FS, Start, I, E, + FS.usesPositionalArg() ? 0 : &argIndex)) + return true; if (I == E) { // No more characters left? @@ -214,44 +343,53 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, default: break; // C99: 7.19.6.1 (section 8). - case 'd': k = ConversionSpecifier::dArg; break; - case 'i': k = ConversionSpecifier::iArg; break; - case 'o': k = ConversionSpecifier::oArg; break; - case 'u': k = ConversionSpecifier::uArg; break; - case 'x': k = ConversionSpecifier::xArg; break; - case 'X': k = ConversionSpecifier::XArg; break; - case 'f': k = ConversionSpecifier::fArg; break; - case 'F': k = ConversionSpecifier::FArg; break; - case 'e': k = ConversionSpecifier::eArg; break; + case '%': k = ConversionSpecifier::PercentArg; break; + case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; - case 'g': k = ConversionSpecifier::gArg; break; + case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; + case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; - case 'A': k = ConversionSpecifier::AArg; break; case 'c': k = ConversionSpecifier::IntAsCharArg; break; - case 's': k = ConversionSpecifier::CStrArg; break; - case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 'd': k = ConversionSpecifier::dArg; break; + case 'e': k = ConversionSpecifier::eArg; break; + case 'f': k = ConversionSpecifier::fArg; break; + case 'g': k = ConversionSpecifier::gArg; break; + case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::OutIntPtrArg; break; - case '%': k = ConversionSpecifier::PercentArg; break; + case 'o': k = ConversionSpecifier::oArg; break; + case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 's': k = ConversionSpecifier::CStrArg; break; + case 'u': k = ConversionSpecifier::uArg; break; + case 'x': k = ConversionSpecifier::xArg; break; + // Mac OS X (unicode) specific + case 'C': k = ConversionSpecifier::CArg; break; + case 'S': k = ConversionSpecifier::UnicodeStrArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; } - FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k)); + ConversionSpecifier CS(conversionPosition, k); + FS.setConversionSpecifier(CS); + if (CS.consumesDataArgument() && !FS.usesPositionalArg()) + FS.setArgIndex(argIndex++); if (k == ConversionSpecifier::InvalidSpecifier) { - H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); - return false; // Keep processing format specifiers. + // Assume the conversion takes one argument. + return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); } return FormatSpecifierResult(Start, FS); } bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, const char *I, const char *E) { + + unsigned argIndex = 0; + // Keep looking for a format specifier until we have exhausted the string. while (I != E) { - const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E); + const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -345,8 +483,10 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { if (!PT) return false; - QualType pointeeTy = PT->getPointeeType(); - return pointeeTy == C.WCharTy; + QualType pointeeTy = + C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); + + return pointeeTy == C.getWCharType(); } return false; @@ -359,7 +499,7 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { if (K == CStrTy) return C.getPointerType(C.CharTy); if (K == WCStrTy) - return C.getPointerType(C.WCharTy); + return C.getPointerType(C.getWCharType()); if (K == ObjCPointerTy) return C.ObjCBuiltinIdTy; @@ -426,9 +566,17 @@ ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { return Ctx.DoubleTy; } - if (CS.getKind() == ConversionSpecifier::CStrArg) - return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy - : ArgTypeResult::CStrTy); + switch (CS.getKind()) { + case ConversionSpecifier::CStrArg: + return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); + case ConversionSpecifier::UnicodeStrArg: + // FIXME: This appears to be Mac OS X specific. + return ArgTypeResult::WCStrTy; + case ConversionSpecifier::CArg: + return Ctx.WCharTy; + default: + break; + } // FIXME: Handle other cases. return ArgTypeResult(); diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp new file mode 100644 index 0000000000000..f959e5cd43e16 --- /dev/null +++ b/lib/Analysis/ReachableCode.cpp @@ -0,0 +1,278 @@ +//=- ReachableCodePathInsensitive.cpp ---------------------------*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a flow-sensitive, path-insensitive analysis of +// determining reachable blocks within a CFG. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/Analyses/ReachableCode.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; + +static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, + SourceRange &R2) { + const Stmt *S = 0; + unsigned sn = 0; + R1 = R2 = SourceRange(); + +top: + if (sn < b.size()) + S = b[sn].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(S); + if (BO->getOpcode() == BinaryOperator::Comma) { + if (sn+1 < b.size()) + return b[sn+1].getStmt()->getLocStart(); + const CFGBlock *n = &b; + while (1) { + if (n->getTerminator()) + return n->getTerminator()->getLocStart(); + if (n->succ_size() != 1) + return SourceLocation(); + n = n[0].succ_begin()[0]; + if (n->pred_size() != 1) + return SourceLocation(); + if (!n->empty()) + return n[0][0].getStmt()->getLocStart(); + } + } + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return BO->getOperatorLoc(); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(S); + R1 = UO->getSubExpr()->getSourceRange(); + return UO->getOperatorLoc(); + } + case Expr::CompoundAssignOperatorClass: { + const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); + R1 = CAO->getLHS()->getSourceRange(); + R2 = CAO->getRHS()->getSourceRange(); + return CAO->getOperatorLoc(); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(S); + return CO->getQuestionLoc(); + } + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(S); + R1 = ME->getSourceRange(); + return ME->getMemberLoc(); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); + R1 = ASE->getLHS()->getSourceRange(); + R2 = ASE->getRHS()->getSourceRange(); + return ASE->getRBracketLoc(); + } + case Expr::CStyleCastExprClass: { + const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); + R1 = CSC->getSubExpr()->getSourceRange(); + return CSC->getLParenLoc(); + } + case Expr::CXXFunctionalCastExprClass: { + const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); + R1 = CE->getSubExpr()->getSourceRange(); + return CE->getTypeBeginLoc(); + } + case Expr::ImplicitCastExprClass: + ++sn; + goto top; + case Stmt::CXXTryStmtClass: { + return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); + } + default: ; + } + R1 = S->getSourceRange(); + return S->getLocStart(); +} + +static SourceLocation MarkLiveTop(const CFGBlock *Start, + llvm::BitVector &reachable, + SourceManager &SM) { + + // Prep work worklist. + llvm::SmallVector<const CFGBlock*, 32> WL; + WL.push_back(Start); + + SourceRange R1, R2; + SourceLocation top = GetUnreachableLoc(*Start, R1, R2); + + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } + + // Solve + while (!WL.empty()) { + const CFGBlock *item = WL.back(); + WL.pop_back(); + + SourceLocation c = GetUnreachableLoc(*item, R1, R2); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } + + reachable.set(item->getBlockID()); + for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); + I != E; ++I) + if (const CFGBlock *B = *I) { + unsigned blockID = B->getBlockID(); + if (!reachable[blockID]) { + reachable.set(blockID); + WL.push_back(B); + } + } + } + + return top; +} + +static int LineCmp(const void *p1, const void *p2) { + SourceLocation *Line1 = (SourceLocation *)p1; + SourceLocation *Line2 = (SourceLocation *)p2; + return !(*Line1 < *Line2); +} + +namespace { +struct ErrLoc { + SourceLocation Loc; + SourceRange R1; + SourceRange R2; + ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) + : Loc(l), R1(r1), R2(r2) { } +}; +} +namespace clang { namespace reachable_code { + +/// ScanReachableFromBlock - Mark all blocks reachable from Start. +/// Returns the total number of blocks that were marked reachable. +unsigned ScanReachableFromBlock(const CFGBlock &Start, + llvm::BitVector &Reachable) { + unsigned count = 0; + llvm::SmallVector<const CFGBlock*, 32> WL; + + // Prep work queue + Reachable.set(Start.getBlockID()); + ++count; + WL.push_back(&Start); + + // Find the reachable blocks from 'Start'. + while (!WL.empty()) { + const CFGBlock *item = WL.back(); + WL.pop_back(); + + // Look at the successors and mark then reachable. + for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); + I != E; ++I) + if (const CFGBlock *B = *I) { + unsigned blockID = B->getBlockID(); + if (!Reachable[blockID]) { + Reachable.set(blockID); + ++count; + WL.push_back(B); + } + } + } + return count; +} + +void FindUnreachableCode(AnalysisContext &AC, Callback &CB) { + CFG *cfg = AC.getCFG(); + if (!cfg) + return; + + // Scan for reachable blocks. + llvm::BitVector reachable(cfg->getNumBlockIDs()); + unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); + + // If there are no unreachable blocks, we're done. + if (numReachable == cfg->getNumBlockIDs()) + return; + + SourceRange R1, R2; + + llvm::SmallVector<ErrLoc, 24> lines; + bool AddEHEdges = AC.getAddEHEdges(); + + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!reachable[b.getBlockID()]) { + if (b.pred_empty()) { + if (!AddEHEdges && dyn_cast_or_null<CXXTryStmt>(b.getTerminator())) { + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + numReachable += ScanReachableFromBlock(b, reachable); + continue; + } + SourceLocation c = GetUnreachableLoc(b, R1, R2); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + reachable.set(b.getBlockID()); + ++numReachable; + continue; + } + lines.push_back(ErrLoc(c, R1, R2)); + // Avoid excessive errors by marking everything reachable from here + numReachable += ScanReachableFromBlock(b, reachable); + } + } + } + + if (numReachable < cfg->getNumBlockIDs()) { + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!reachable[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, + AC.getASTContext().getSourceManager()), + SourceRange(), SourceRange())); + } + } + + llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); + + for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end(); + I != E; ++I) + if (I->Loc.isValid()) + CB.HandleUnreachable(I->Loc, I->R1, I->R2); +} + +}} // end namespace clang::reachable_code diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index bdc0e7c621f7f..7a628642dc99e 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -134,8 +134,12 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) { VarDecl *VD = dyn_cast<VarDecl>(*I); if (VD && VD->isBlockVarDecl()) { - if (Stmt* I = VD->getInit()) - V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized; + if (Stmt* I = VD->getInit()) { + // Visit the subexpression to check for uses of uninitialized values, + // even if we don't propagate that value. + bool isSubExprUninit = Visit(I); + V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized; + } else { // Special case for declarations of array types. For things like: // |