nickdesaulniers updated this revision to Diff 307218.
nickdesaulniers added a comment.
- git-clang-format HEAD~
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D91895/new/
https://reviews.llvm.org/D91895
Files:
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/SemaCXX/switch-implicit-fallthrough-blocks.cpp
clang/test/SemaCXX/switch-implicit-fallthrough.cpp
Index: clang/test/SemaCXX/switch-implicit-fallthrough.cpp
===================================================================
--- clang/test/SemaCXX/switch-implicit-fallthrough.cpp
+++ clang/test/SemaCXX/switch-implicit-fallthrough.cpp
@@ -33,7 +33,7 @@
}
case 6: // 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}}
n += 300;
- case 66: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'break;' to avoid fall-through}}
+ case 66:
case 67:
case 68:
break;
@@ -151,23 +151,23 @@
#define MY_CASE2(X, Y, U, V) case X: Y; case U: V
int fallthrough_macro1(int n) {
- MY_SWITCH(n, 13, n *= 2, 14, break) // expected-warning{{unannotated fall-through between switch labels}}
+ MY_SWITCH(n, 13, n *= 2, 14, break)
switch (n + 1) {
MY_CASE(33, n += 2);
- MY_CASE(44, break); // expected-warning{{unannotated fall-through between switch labels}}
- MY_CASE(55, n += 3);
+ MY_CASE(44, n += 3); // expected-warning{{unannotated fall-through between switch labels}}
+ MY_CASE(55, break);
}
switch (n + 3) {
MY_CASE(333, return 333);
- MY_CASE2(444, n += 44, 4444, break); // expected-warning{{unannotated fall-through between switch labels}}
+ MY_CASE2(444, n += 44, 4444, break);
MY_CASE(555, n += 33);
}
- MY_SWITCH2(n + 4, MY_CASE(17, n *= 3), MY_CASE(19, break)) // expected-warning{{unannotated fall-through between switch labels}}
+ MY_SWITCH2(n + 4, MY_CASE(17, n *= 3), MY_CASE(19, break))
- MY_SWITCH2(n + 5, MY_CASE(21, break), MY_CASE2(23, n *= 7, 25, break)) // expected-warning{{unannotated fall-through between switch labels}}
+ MY_SWITCH2(n + 5, MY_CASE(21, break), MY_CASE2(23, n *= 7, 25, break))
return n;
}
@@ -237,9 +237,15 @@
[[clang::fallthrough]]; // no diagnostics
case 1:
x++;
+ case 2: // no diagnostics
+ break;
+ case 3:
+ x++;
default: // \
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}}
+ x++;
break;
}
}
@@ -257,9 +263,15 @@
[[clang::fallthrough]]; // no diagnostics
case 1:
x++;
+ case 2: // no diagnostics
+ break;
+ case 3:
+ x++;
default: // \
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}}
+ x++;
break;
}
};
@@ -279,6 +291,106 @@
}
}
+void bar(void);
+
+// Should not warn.
+void test0(int x) {
+ switch (x) {
+ case 0:
+ bar();
+ default:
+ break;
+ }
+}
+
+// should not warn.
+void test1(int x) {
+ switch (x) {
+ case 0:
+ bar();
+ default:
+ return;
+ }
+}
+
+// should not warn.
+void test2(int x) {
+ switch (x) {
+ case 0:
+ bar();
+ default:
+ goto y;
+ }
+y:;
+}
+
+void test3(int x) {
+ switch (x) {
+ case 0:
+ bar();
+ default: // \
+ // 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}}
+ bar();
+ break;
+ }
+}
+
+// Should not warn.
+int y;
+void test4(int x) {
+ switch (x) {
+ case 0:
+ if (y)
+ bar();
+ default:
+ break;
+ }
+}
+
+// Should not warn.
+void test5(int x) {
+ switch (x) {
+ case 0:
+ ++x;
+ case 1:
+ case 2:
+ case 3:
+ break;
+ }
+}
+
+// Should not warn.
+// TODO: GCC does not warn
+void test6(int x) {
+ switch (x) {
+ case 0:
+ bar();
+ default: // \
+ // 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}}
+ ;
+ }
+ bar();
+ bar();
+}
+
+// Should warn.
+void test7(int x) {
+ switch (x) {
+ case 3:
+ ++x;
+ case 4: // \
+ // 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}}
+ do {
+ } while (1);
+ break;
+ }
+}
int fallthrough_placement_error(int n) {
switch (n) {
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
Index: clang/test/SemaCXX/switch-implicit-fallthrough-blocks.cpp
===================================================================
--- clang/test/SemaCXX/switch-implicit-fallthrough-blocks.cpp
+++ clang/test/SemaCXX/switch-implicit-fallthrough-blocks.cpp
@@ -7,11 +7,17 @@
case 0:
x++;
[[clang::fallthrough]]; // no diagnostics
+ case 2:
+ x++;
+ case 3: // no diagnostics
+ break;
case 1:
x++;
default: // \
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}}
+ x++;
break;
}
};
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1087,6 +1087,31 @@
}
}
+ // Does this CFGBlock only contain a single statement which is a return?
+ bool isEmptyCaseWithReturn(const CFGBlock *B) {
+ if (B->size() == 1 && B->succ_size() == 1)
+ if (Optional<clang::CFGStmt> CS = B->front().getAs<CFGStmt>())
+ if (const Stmt *S = CS->getStmt())
+ if (isa<ReturnStmt>(S))
+ return true;
+ return false;
+ }
+
+ bool shouldntWarnSucessors(const CFGBlock *B) {
+ return llvm::any_of(B->succs(),
+ [this](const CFGBlock::AdjacentBlock &Succ) {
+ if (const CFGBlock *S = Succ.getReachableBlock()) {
+ if (S->size())
+ return isEmptyCaseWithReturn(S);
+ if (const Stmt *T = S->getTerminatorStmt())
+ if (isa<BreakStmt>(T) || isa<GotoStmt>(T))
+ return true;
+ return shouldntWarnSucessors(S);
+ }
+ return false;
+ });
+ }
+
bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt,
bool IsTemplateInstantiation) {
assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
@@ -1149,6 +1174,9 @@
continue; // Fallthrough annotation, good.
}
+ if (shouldntWarnSucessors(P))
+ continue;
+
if (!LastStmt) { // This block contains no executable statements.
// Traverse its predecessors.
std::copy(P->pred_begin(), P->pred_end(),
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits