diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1148,6 +1148,11 @@ continue; } + if (isFollowedByFallThroughComment(LastStmt)) { + ++AnnotatedCnt; + continue; // Fallthrough comment, good. + } + ++UnannotatedCnt; } return !!UnannotatedCnt; @@ -1208,10 +1213,41 @@ return nullptr; } + bool isFollowedByFallThroughComment(const Stmt *Statement) { + // Try to detect whether the fallthough is marked by a comment like + // /*FALLTHOUGH*/. + bool Invalid; + const char *SourceData = S.getSourceManager().getCharacterData( + Statement->getEndLoc(), &Invalid); + if (Invalid) + return false; + const char *LineStart = SourceData; + for (;;) { + LineStart = strchr(LineStart, '\n'); + if (LineStart == nullptr) + return false; + ++LineStart; // Start of next line. + const char *LineEnd = strchr(LineStart, '\n'); + StringRef Line(LineStart, + LineEnd ? LineEnd - LineStart : strlen(LineStart)); + if (LineStart == LineEnd || + Line.find_first_not_of(" \t\r") == StringRef::npos) + continue; // Whitespace-only line. + if (!FallthroughRegex.isValid()) + FallthroughRegex = + llvm::Regex("(/\\*[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*\\*/)" + "|(//[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*)", + llvm::Regex::IgnoreCase); + assert(FallthroughRegex.isValid()); + return FallthroughRegex.match(Line); + } + } + bool FoundSwitchStatements; AttrStmts FallthroughStmts; Sema &S; llvm::SmallPtrSet ReachableBlocks; + llvm::Regex FallthroughRegex; }; } // anonymous namespace diff --git a/clang/test/Sema/fallthrough-comment.c b/clang/test/Sema/fallthrough-comment.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/fallthrough-comment.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -Wimplicit-fallthrough %s + +int fallthrough_comment(int n) { + switch (n) { + case 0: + n++; + // FALLTHROUGH + case 1: + n++; + + /*fall-through.*/ + + case 2: + n++; + case 3: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '__attribute__((fallthrough));' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}} + n++; + break; + } + return n; +}