diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0ccb8f2b1d5f..d81e187bb304 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1328,14 +1328,47 @@ static void MarkLive(CFGBlock *e, llvm::BitVector &live) { } } +static SourceLocation GetUnreachableLoc(CFGBlock &b) { + Stmt *S; + if (!b.empty()) + S = b[0].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + BinaryOperator *Op = cast(S); + if (Op->getOpcode() == BinaryOperator::Comma) { + if (b.size() < 2) { + 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(); + } + } + return b[1].getStmt()->getLocStart(); + } + } + default: ; + } + return S->getLocStart(); +} + static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, SourceManager &SM) { std::queue workq; // Prep work queue workq.push(e); - SourceLocation top; - if (!e->empty()) - top = e[0][0].getStmt()->getLocStart(); + SourceLocation top = GetUnreachableLoc(*e); bool FromMainFile = false; bool FromSystemHeader = false; bool TopValid = false; @@ -1348,11 +1381,7 @@ static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, while (!workq.empty()) { CFGBlock *item = workq.front(); workq.pop(); - SourceLocation c; - if (!item->empty()) - c = item[0][0].getStmt()->getLocStart(); - else if (item->getTerminator()) - c = item->getTerminator()->getLocStart(); + SourceLocation c = GetUnreachableLoc(*item); if (c.isValid() && (!TopValid || (SM.isFromMainFile(c) && !FromMainFile) @@ -1412,10 +1441,14 @@ void Sema::CheckUnreachable(AnalysisContext &AC) { CFGBlock &b = **I; if (!live[b.getBlockID()]) { if (b.pred_begin() == b.pred_end()) { - if (!b.empty()) - lines.push_back(b[0].getStmt()->getLocStart()); - else if (b.getTerminator()) - lines.push_back(b.getTerminator()->getLocStart()); + SourceLocation c = GetUnreachableLoc(b); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + live.set(b.getBlockID()); + continue; + } + lines.push_back(c); // Avoid excessive errors by marking everything reachable from here MarkLive(&b, live); } diff --git a/clang/test/Sema/warn-unreachable.c b/clang/test/Sema/warn-unreachable.c index 2c123d0b0fc4..08ad6536987b 100644 --- a/clang/test/Sema/warn-unreachable.c +++ b/clang/test/Sema/warn-unreachable.c @@ -1,5 +1,9 @@ // RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wunreachable-code +int halt() __attribute__((noreturn)); +int live(); +int dead(); + void test1() { goto c; d: @@ -18,3 +22,55 @@ void test1() { goto d; f: ; } + +void test2() { + switch (live()) { + case 1: + halt(), + dead(); // expected-warning {{will never be executed}} + + case 2: + live(), + halt(), + dead(); // expected-warning {{will never be executed}} + + case 3: + live(), + halt(); + dead(); // expected-warning {{will never be executed}} + + case 4: + a4: + live(), + halt(); + goto a4; // expected-warning {{will never be executed}} + + case 5: + goto a5; + c5: + dead(); // expected-warning {{will never be executed}} + goto b5; + a5: + live(), + halt(); + b5: + goto c5; + + case 6: + if (live()) + goto e6; + live(), + halt(); + d6: + dead(); // expected-warning {{will never be executed}} + goto b6; + c6: + dead(); + goto b6; + e6: + live(), + halt(); + b6: + goto c6; + } +}