summaryrefslogtreecommitdiff
path: root/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/AnalysisContext.cpp12
-rw-r--r--lib/Analysis/CFG.cpp33
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/LiveVariables.cpp21
-rw-r--r--lib/Analysis/PrintfFormatString.cpp224
-rw-r--r--lib/Analysis/ReachableCode.cpp278
-rw-r--r--lib/Analysis/UninitializedValues.cpp8
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:
//