summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2014-03-05 00:01:17 +0000
committerTed Kremenek <kremenek@apple.com>2014-03-05 00:01:17 +0000
commit6d9bb56cd35f865662755936977f4bc691289e2b (patch)
treeb5081af0710df72e1812f81545b4e693f59d2fff /clang/lib/Analysis
parent1e57976ec0f11f2b606034b33415692c60cf9514 (diff)
downloadbcm5719-llvm-6d9bb56cd35f865662755936977f4bc691289e2b.tar.gz
bcm5719-llvm-6d9bb56cd35f865662755936977f4bc691289e2b.zip
[-Wunreachable-code] Don't warn about dead code guarded by a "configuration value".
Some unreachable code is only "sometimes unreachable" because it is guarded by a configuration value that is determined at compile time and is always constant. Sometimes those represent real bugs, but often they do not. This patch causes the reachability analysis to cover such branches even if they are technically unreachable in the CFG itself. There are some conservative heuristics at play here to determine a "configuration value"; these are intended to be refined over time. llvm-svn: 202912
Diffstat (limited to 'clang/lib/Analysis')
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp82
1 files changed, 73 insertions, 9 deletions
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index b0e92504260..5baaa006777 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -351,6 +351,56 @@ namespace clang { namespace reachable_code {
void Callback::anchor() { }
+/// Returns true if the statement is expanded from a configuration macro.
+static bool isExpandedFromConfigurationMacro(const Stmt *S) {
+ // FIXME: This is not very precise. Here we just check to see if the
+ // value comes from a macro, but we can do much better. This is likely
+ // to be over conservative. This logic is factored into a separate function
+ // so that we can refine it later.
+ SourceLocation L = S->getLocStart();
+ return L.isMacroID();
+}
+
+/// Returns true if the statement represents a configuration value.
+///
+/// A configuration value is something usually determined at compile-time
+/// to conditionally always execute some branch. Such guards are for
+/// "sometimes unreachable" code. Such code is usually not interesting
+/// to report as unreachable, and may mask truly unreachable code within
+/// those blocks.
+static bool isConfigurationValue(const Stmt *S) {
+ if (!S)
+ return false;
+
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreParenCasts();
+
+ switch (S->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ return isExpandedFromConfigurationMacro(S);
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ return true;
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *B = cast<BinaryOperator>(S);
+ return (B->isLogicalOp() || B->isRelationalOp()) &&
+ (isConfigurationValue(B->getLHS()) ||
+ isConfigurationValue(B->getRHS()));
+ }
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(S);
+ return UO->getOpcode() == UO_LNot &&
+ isConfigurationValue(UO->getSubExpr());
+ }
+ default:
+ return false;
+ }
+}
+
+/// Returns true if we should always explore all successors of a block.
+static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B) {
+ return isConfigurationValue(B->getTerminatorCondition());
+}
+
unsigned ScanReachableFromBlock(const CFGBlock *Start,
llvm::BitVector &Reachable) {
unsigned count = 0;
@@ -370,13 +420,28 @@ unsigned ScanReachableFromBlock(const CFGBlock *Start,
// Find the reachable blocks from 'Start'.
while (!WL.empty()) {
const CFGBlock *item = WL.pop_back_val();
-
+
+ // There are cases where we want to treat all successors as reachable.
+ // The idea is that some "sometimes unreachable" code is not interesting,
+ // and that we should forge ahead and explore those branches anyway.
+ // This allows us to potentially uncover some "always unreachable" code
+ // within the "sometimes unreachable" code.
+ bool TreatAllSuccessorsAsReachable = shouldTreatSuccessorsAsReachable(item);
+
// Look at the successors and mark then reachable.
for (CFGBlock::const_succ_iterator I = item->succ_begin(),
E = item->succ_end(); I != E; ++I) {
const CFGBlock *B = *I;
- if (!B) {
- //
+ if (!B) do {
+ const CFGBlock *UB = I->getPossiblyUnreachableBlock();
+ if (!UB)
+ break;
+
+ if (TreatAllSuccessorsAsReachable) {
+ B = UB;
+ break;
+ }
+
// For switch statements, treat all cases as being reachable.
// There are many cases where a switch can contain values that
// are not in an enumeration but they are still reachable because
@@ -391,13 +456,12 @@ unsigned ScanReachableFromBlock(const CFGBlock *Start,
// this we can either put more heuristics here, or possibly retain
// that information in the CFG itself.
//
- if (const CFGBlock *UB = I->getPossiblyUnreachableBlock()) {
- const Stmt *Label = UB->getLabel();
- if (Label && isa<SwitchCase>(Label)) {
- B = UB;
- }
- }
+ const Stmt *Label = UB->getLabel();
+ if (Label && isa<SwitchCase>(Label))
+ B = UB;
}
+ while (false);
+
if (B) {
unsigned blockID = B->getBlockID();
if (!Reachable[blockID]) {
OpenPOWER on IntegriCloud