aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/Analyses/ReachableCode.h1
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp20
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp6
-rw-r--r--clang/test/SemaCXX/unreachable-code.cpp4
-rw-r--r--clang/test/SemaCXX/warn-unreachable.cpp12
-rw-r--r--clang/test/SemaObjC/warn-unreachable.m9
8 files changed, 55 insertions, 4 deletions
diff --git a/clang/include/clang/Analysis/Analyses/ReachableCode.h b/clang/include/clang/Analysis/Analyses/ReachableCode.h
index ed0d711..a328ea2 100644
--- a/clang/include/clang/Analysis/Analyses/ReachableCode.h
+++ b/clang/include/clang/Analysis/Analyses/ReachableCode.h
@@ -41,6 +41,7 @@ namespace reachable_code {
enum UnreachableKind {
UK_Return,
UK_Break,
+ UK_Loop_Increment,
UK_Other
};
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index c7ea65f..8066ed5 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -430,7 +430,9 @@ def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">;
// least actively used, with more noisy versions of the warning covered
// under separate flags.
//
-def UnreachableCode : DiagGroup<"unreachable-code">;
+def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">;
+def UnreachableCode : DiagGroup<"unreachable-code",
+ [UnreachableCodeLoopIncrement]>;
def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">;
def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">;
def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive",
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7bc66be..5e45930 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -370,6 +370,9 @@ def warn_unreachable_break : Warning<
def warn_unreachable_return : Warning<
"'return' will never be executed">,
InGroup<UnreachableCodeReturn>, DefaultIgnore;
+def warn_unreachable_loop_increment : Warning<
+ "loop will run at most once (loop increment never executed)">,
+ InGroup<UnreachableCodeLoopIncrement>, DefaultIgnore;
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 4220000..53e03de 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -529,6 +529,26 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
UK = reachable_code::UK_Return;
}
+ if (UK == reachable_code::UK_Other) {
+ // Check if the dead code is part of the "loop target" of
+ // a for/for-range loop. This is the block that contains
+ // the increment code.
+ if (const Stmt *LoopTarget = B->getLoopTarget()) {
+ SourceLocation Loc = LoopTarget->getLocStart();
+ SourceRange R1(Loc, Loc), R2;
+
+ if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
+ const Expr *Inc = FS->getInc();
+ Loc = Inc->getLocStart();
+ R2 = Inc->getSourceRange();
+ }
+
+ CB.HandleUnreachable(reachable_code::UK_Loop_Increment,
+ Loc, SourceRange(Loc, Loc), R2);
+ return;
+ }
+ }
+
SourceRange R1, R2;
SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
CB.HandleUnreachable(UK, Loc, R1, R2);
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 389109a..ecf6d51 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -76,6 +76,9 @@ namespace {
case reachable_code::UK_Return:
diag = diag::warn_unreachable_return;
break;
+ case reachable_code::UK_Loop_Increment:
+ diag = diag::warn_unreachable_loop_increment;
+ break;
case reachable_code::UK_Other:
break;
}
@@ -1688,7 +1691,8 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
DefaultPolicy.enableCheckUnreachable =
isEnabled(D, warn_unreachable) ||
isEnabled(D, warn_unreachable_break) ||
- isEnabled(D, warn_unreachable_return);
+ isEnabled(D, warn_unreachable_return) ||
+ isEnabled(D, warn_unreachable_loop_increment);
DefaultPolicy.enableThreadSafetyAnalysis =
isEnabled(D, warn_double_lock);
diff --git a/clang/test/SemaCXX/unreachable-code.cpp b/clang/test/SemaCXX/unreachable-code.cpp
index 5016c3f..fd006c0 100644
--- a/clang/test/SemaCXX/unreachable-code.cpp
+++ b/clang/test/SemaCXX/unreachable-code.cpp
@@ -5,7 +5,7 @@ int bar();
int test1() {
for (int i = 0;
i != 10;
- ++i) { // expected-warning {{will never be executed}}
+ ++i) { // expected-warning {{loop will run at most once (loop increment never executed)}}
if (j == 23) // missing {}'s
bar();
return 1;
@@ -17,7 +17,7 @@ int test1() {
int test1_B() {
for (int i = 0;
i != 10;
- ++i) { // expected-warning {{will never be executed}}
+ ++i) { // expected-warning {{loop will run at most once (loop increment never executed)}}
if (j == 23) // missing {}'s
bar();
return 1;
diff --git a/clang/test/SemaCXX/warn-unreachable.cpp b/clang/test/SemaCXX/warn-unreachable.cpp
index eab8d8e6..8acaf42 100644
--- a/clang/test/SemaCXX/warn-unreachable.cpp
+++ b/clang/test/SemaCXX/warn-unreachable.cpp
@@ -282,3 +282,15 @@ void test_static_class_var(Frodo &F) {
somethingToCall(); // no-warning
}
+void test_unreachable_for_null_increment() {
+ for (unsigned i = 0; i < 10 ; ) // no-warning
+ break;
+}
+
+void test_unreachable_forrange_increment() {
+ int x[10] = { 0 };
+ for (auto i : x) { // expected-warning {{loop will run at most once (loop increment never executed)}}
+ break;
+ }
+}
+
diff --git a/clang/test/SemaObjC/warn-unreachable.m b/clang/test/SemaObjC/warn-unreachable.m
index 979b905..859bd00 100644
--- a/clang/test/SemaObjC/warn-unreachable.m
+++ b/clang/test/SemaObjC/warn-unreachable.m
@@ -40,3 +40,12 @@ int test_CONFIG() {
else
return 0;
}
+
+// FIXME: This should at some point report a warning
+// that the loop increment is unreachable.
+void test_loop_increment(id container) {
+ for (id x in container) { // no-warning
+ break;
+ }
+}
+