Split a chunk of -Wconditional-uninitialized warnings out into a separate flag,
-Wsometimes-uninitialized. This detects cases where an explicitly-written branch
inevitably leads to an uninitialized variable use (so either the branch is dead
code or there is an uninitialized use bug).

This chunk of warnings tentatively lives within -Wuninitialized, in order to
give it more visibility to existing Clang users.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@157458 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/uninit-sometimes.cpp b/test/Analysis/uninit-sometimes.cpp
new file mode 100644
index 0000000..0c77f89
--- /dev/null
+++ b/test/Analysis/uninit-sometimes.cpp
@@ -0,0 +1,258 @@
+// RUN: %clang_cc1 -std=gnu++11 -Wsometimes-uninitialized -verify %s
+
+bool maybe();
+
+int test_if_false(bool b) {
+  int x; // expected-note {{variable}}
+  if (b) x = 1; // expected-note {{whenever 'if' condition is false}}
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_if_true(bool b) {
+  int x; // expected-note {{variable}}
+  if (b) {} // expected-note {{whenever 'if' condition is true}}
+  else x = 1;
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_while_false(bool b) {
+  int x; // expected-note {{variable}}
+  while (b) { // expected-note {{whenever 'while' loop exits because its condition is false}}
+    if (maybe()) {
+      x = 1;
+      break;
+    }
+  };
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_while_true(bool b) {
+  int x; // expected-note {{variable}}
+  while (b) { // expected-note {{whenever 'while' loop is entered}}
+label:
+    return x; // expected-warning {{sometimes uninit}}
+  }
+  x = 0;
+  goto label;
+}
+
+int test_do_while_false(bool b) {
+  int x; // expected-note {{variable}}
+  do {
+    if (maybe()) {
+      x = 1;
+      break;
+    }
+  } while (b); // expected-note {{whenever 'do' loop exits because its condition is false}}
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_do_while_true(bool b) {
+  int x; // expected-note {{variable}}
+goto label2;
+  do {
+label1:
+    return x; // expected-warning {{sometimes uninit}}
+label2: ;
+  } while (b); // expected-note {{whenever 'do' loop condition is true}}
+  x = 0;
+  goto label1;
+}
+
+int test_for_false(int k) {
+  int x; // expected-note {{variable}}
+  for (int n = 0;
+       n < k; // expected-note {{whenever 'for' loop exits because its condition is false}}
+       ++n) {
+    if (maybe()) {
+      x = n;
+      break;
+    }
+  }
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_for_true(int k) {
+  int x; // expected-note {{variable}}
+  int n = 0;
+  for (;
+       n < k; // expected-note {{whenever 'for' loop is entered}}
+       ++n) {
+label:
+    return x; // expected-warning {{sometimes uninit}}
+  }
+  x = 1;
+  goto label;
+}
+
+int test_for_range_false(int k) {
+  int arr[3] = { 1, 2, 3 };
+  int x; // expected-note {{variable}}
+  for (int &a : arr) { // expected-note {{whenever 'for' loop exits because its condition is false}}
+    if (a == k) {
+      x = &a - arr;
+      break;
+    }
+  }
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_for_range_true(int k) {
+  int arr[3] = { 1, 2, 3 };
+  int x; // expected-note {{variable}}
+  for (int &a : arr) { // expected-note {{whenever 'for' loop is entered}}
+    goto label;
+  }
+  x = 0;
+label:
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_conditional_false(int k) {
+  int x; // expected-note {{variable}}
+  (void)(
+      maybe() // expected-note {{whenever '?:' condition is false}}
+      ? x = 1 : 0);
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_conditional_true(int k) {
+  int x; // expected-note {{variable}}
+  (void)(
+      maybe() // expected-note {{whenever '?:' condition is true}}
+      ? 0 : x = 1);
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_logical_and_false(int k) {
+  int x; // expected-note {{variable}}
+  maybe() // expected-note {{whenever '&&' condition is false}}
+      && (x = 1);
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_logical_and_true(int k) {
+  int x; // expected-note {{variable}}
+  maybe() // expected-note {{whenever '&&' condition is true}}
+      && ({ goto skip_init; 0; });
+  x = 1;
+skip_init:
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_logical_or_false(int k) {
+  int x; // expected-note {{variable}}
+  maybe() // expected-note {{whenever '||' condition is false}}
+      || ({ goto skip_init; 0; });
+  x = 1;
+skip_init:
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_logical_or_true(int k) {
+  int x; // expected-note {{variable}}
+  maybe() // expected-note {{whenever '||' condition is true}}
+      || (x = 1);
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_switch_case(int k) {
+  int x; // expected-note {{variable}}
+  switch (k) {
+  case 0:
+    x = 0;
+    break;
+  case 1: // expected-note {{whenever switch case is taken}}
+    break;
+  }
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_switch_default(int k) {
+  int x; // expected-note {{variable}}
+  switch (k) {
+  case 0:
+    x = 0;
+    break;
+  case 1:
+    x = 1;
+    break;
+  default: // expected-note {{whenever switch default is taken}}
+    break;
+  }
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_switch_suppress_1(int k) {
+  int x;
+  switch (k) {
+  case 0:
+    x = 0;
+    break;
+  case 1:
+    x = 1;
+    break;
+  }
+  return x; // no-warning
+}
+
+int test_switch_suppress_2(int k) {
+  int x;
+  switch (k) {
+  case 0:
+  case 1:
+    switch (k) {
+    case 0:
+      return 0;
+    case 1:
+      return 1;
+    }
+  case 2:
+  case 3:
+    x = 1;
+  }
+  return x; // no-warning
+}
+
+int test_multiple_notes(int k) {
+  int x; // expected-note {{variable}}
+  if (k > 0) {
+    if (k == 5)
+      x = 1;
+    else if (k == 2) // expected-note {{whenever 'if' condition is false}}
+      x = 2;
+  } else {
+    if (k == -5)
+      x = 3;
+    else if (k == -2) // expected-note {{whenever 'if' condition is false}}
+      x = 4;
+  }
+  return x; // expected-warning {{sometimes uninit}}
+}
+
+int test_no_false_positive_1(int k) {
+  int x;
+  if (k)
+    x = 5;
+  while (!k)
+    maybe();
+  return x;
+}
+
+int test_no_false_positive_2() {
+  int x;
+  bool b = false;
+  if (maybe()) {
+    x = 5;
+    b = true;
+  }
+  return b ? x : 0;
+}
+
+void test_null_pred_succ() {
+  int x; // expected-note {{variable}}
+  if (0) // expected-note {{whenever}}
+    foo: x = 0;
+  if (x) // expected-warning {{sometimes uninit}}
+    goto foo;
+}