From afed1ddb406afe00cb05360c5b8a01e42db3250d Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Wed, 30 Jan 2013 03:49:44 +0000 Subject: [PATCH] Don't warn on fall-through from unreachable code. Summary: A motivating example: class ClassWithDtor { public: ~ClassWithDtor() {} }; void fallthrough3(int n) { switch (n) { case 2: do { ClassWithDtor temp; return; } while (0); // This generates a chain of unreachable CFG blocks. case 3: break; } } Reviewers: rsmith, doug.gregor, alexfh Reviewed By: alexfh CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D330 llvm-svn: 173889 --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 28 ++++++++++++++++-- .../SemaCXX/switch-implicit-fallthrough.cpp | 29 ++++++++++++++----- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 1687f69f47a6..b36223916337 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -702,7 +702,27 @@ namespace { return FallthroughStmts; } + void fillReachableBlocks(CFG *Cfg) { + assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); + std::deque BlockQueue; + + ReachableBlocks.insert(&Cfg->getEntry()); + BlockQueue.push_back(&Cfg->getEntry()); + while (!BlockQueue.empty()) { + const CFGBlock *P = BlockQueue.front(); + BlockQueue.pop_front(); + for (CFGBlock::const_succ_iterator I = P->succ_begin(), + E = P->succ_end(); + I != E; ++I) { + if (ReachableBlocks.insert(*I)) + BlockQueue.push_back(*I); + } + } + } + bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) { + assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); + int UnannotatedCnt = 0; AnnotatedCnt = 0; @@ -726,8 +746,7 @@ namespace { if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) continue; // Case label is preceded with a normal label, good. - if (P->pred_begin() == P->pred_end()) { // The block is unreachable. - // This only catches trivially unreachable blocks. + if (!ReachableBlocks.count(P)) { for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end(); ElIt != ElEnd; ++ElIt) { if (const CFGStmt *CS = ElIt->getAs()){ @@ -816,6 +835,7 @@ namespace { bool FoundSwitchStatements; AttrStmts FallthroughStmts; Sema &S; + llvm::SmallPtrSet ReachableBlocks; }; } @@ -847,7 +867,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, if (!Cfg) return; - int AnnotatedCnt; + FM.fillReachableBlocks(Cfg); for (CFG::reverse_iterator I = Cfg->rbegin(), E = Cfg->rend(); I != E; ++I) { const CFGBlock *B = *I; @@ -856,6 +876,8 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, if (!Label || !isa(Label)) continue; + int AnnotatedCnt; + if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt)) continue; diff --git a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp index 93e724e86c6b..912b21ebfdb5 100644 --- a/clang/test/SemaCXX/switch-implicit-fallthrough.cpp +++ b/clang/test/SemaCXX/switch-implicit-fallthrough.cpp @@ -10,7 +10,7 @@ int fallthrough(int n) { } else if (n - 3) { n = 102; } - case -1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} + case -1: // no warning here, ignore fall-through from unreachable code ; case 0: {// expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} } @@ -39,14 +39,13 @@ int fallthrough(int n) { break; } switch (n / 15) { -label_case_70: - case 70: +label_default: + default: n += 333; + if (n % 10) + goto label_default; break; - case 71: - n += 334; - goto label_case_70; - case 72: + case 70: n += 335; break; } @@ -130,6 +129,22 @@ void fallthrough2(int n) { } } +void fallthrough3(int n) { + switch (n) { + case 1: + do { + return; + } while (0); + case 2: + do { + ClassWithDtor temp; + return; + } while (0); + case 3: + break; + } +} + #define MY_SWITCH(X, Y, Z, U, V) switch (X) { case Y: Z; case U: V; } #define MY_SWITCH2(X, Y, Z) switch (X) { Y; Z; } #define MY_CASE(X, Y) case X: Y -- GitLab