Index: clang/include/clang/Analysis/Analyses/ReachableCode.h =================================================================== --- clang/include/clang/Analysis/Analyses/ReachableCode.h +++ clang/include/clang/Analysis/Analyses/ReachableCode.h @@ -61,8 +61,8 @@ llvm::BitVector &Reachable); void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, - Callback &CB); - + Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled); }} // end namespace clang::reachable_code #endif Index: clang/lib/Analysis/ReachableCode.cpp =================================================================== --- clang/lib/Analysis/ReachableCode.cpp +++ clang/lib/Analysis/ReachableCode.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/ReachableCode.h" +#include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -409,15 +410,16 @@ void enqueue(const CFGBlock *block); unsigned scanBackwards(const CFGBlock *Start, - clang::reachable_code::Callback &CB); + clang::reachable_code::Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled); bool isDeadCodeRoot(const CFGBlock *Block); const Stmt *findDeadCode(const CFGBlock *Block); - void reportDeadCode(const CFGBlock *B, - const Stmt *S, - clang::reachable_code::Callback &CB); + void reportDeadCode(const CFGBlock *B, const Stmt *S, + clang::reachable_code::Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled); }; } @@ -487,8 +489,10 @@ return 0; } -unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, - clang::reachable_code::Callback &CB) { +unsigned +DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, + clang::reachable_code::Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled) { unsigned count = 0; enqueue(Start); @@ -521,7 +525,7 @@ } if (isDeadCodeRoot(Block)) { - reportDeadCode(Block, S, CB); + reportDeadCode(Block, S, CB, UnreachableFallThroughDiagIsEnabled); count += scanMaybeReachableFromBlock(Block, PP, Reachable); } else { @@ -540,7 +544,7 @@ const CFGBlock *Block = I.first; if (Reachable[Block->getBlockID()]) continue; - reportDeadCode(Block, I.second, CB); + reportDeadCode(Block, I.second, CB, UnreachableFallThroughDiagIsEnabled); count += scanMaybeReachableFromBlock(Block, PP, Reachable); } } @@ -613,9 +617,9 @@ return S->getBeginLoc(); } -void DeadCodeScan::reportDeadCode(const CFGBlock *B, - const Stmt *S, - clang::reachable_code::Callback &CB) { +void DeadCodeScan::reportDeadCode( + const CFGBlock *B, const Stmt *S, clang::reachable_code::Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled) { // Classify the unreachable code found, or suppress it in some cases. reachable_code::UnreachableKind UK = reachable_code::UK_Other; @@ -663,6 +667,14 @@ } } + // If S is `[[fallthrough]];` and `-Wunreachable-code-fallthrough` is enabled, + // suppress `code will never be executed` warning to avoid generating + // diagnostic twice + const AttributedStmt *AS = dyn_cast(S); + if (AS && hasSpecificAttr(AS->getAttrs()) && + UnreachableFallThroughDiagIsEnabled) + return; + SourceRange R1, R2; SourceLocation Loc = GetUnreachableLoc(S, R1, R2); CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2); @@ -682,7 +694,8 @@ } void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, - Callback &CB) { + Callback &CB, + const bool UnreachableFallThroughDiagIsEnabled) { CFG *cfg = AC.getCFG(); if (!cfg) @@ -713,11 +726,11 @@ continue; DeadCodeScan DS(reachable, PP, AC.getASTContext()); - numReachable += DS.scanBackwards(block, CB); + numReachable += + DS.scanBackwards(block, CB, UnreachableFallThroughDiagIsEnabled); if (numReachable == cfg->getNumBlockIDs()) return; } } - }} // end namespace clang::reachable_code Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -123,7 +123,10 @@ return; UnreachableCodeHandler UC(S); - reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC); + reachable_code::FindUnreachableCode( + AC, S.getPreprocessor(), UC, + !S.getDiagnostics().isIgnored(diag::warn_unreachable_fallthrough_attr, + SourceLocation())); } namespace { Index: clang/test/Sema/warn-unreachable-fallthrough.c =================================================================== --- /dev/null +++ clang/test/Sema/warn-unreachable-fallthrough.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c2x -Wunreachable-code-fallthrough %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c2x -Wunreachable-code %s +// RUN: %clang_cc1 -fsyntax-only -verify=code -std=c2x -Wunreachable-code -Wno-unreachable-code-fallthrough %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c2x -Wno-unreachable-code -Wunreachable-code-fallthrough %s + +int n; +void f(void){ + switch (n){ + [[fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}} + // code-warning@-1{{never be executed}} + case 1:; + } +}