tests: use clang's -verify instead of FileCheck

Clang uses this for its own diagnostic tests. The nice feature it adds
here is that it fails if clang emits a diagnostic that we don't expect
(and we get to drop a dependency on FileCheck).

This also tweaks and renames file-check-cxx to reflect its new job.

Bug: 131861088
Test: mma
Change-Id: I77f7ce77869edaa23e2401e622ad7007d2fee06c
diff --git a/tests/Android.bp b/tests/Android.bp
index 85bb29a..d65780c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -288,6 +288,7 @@
         // enabled. Since the intent is just to build this, we can get away with
         // passing this flag on its own.
         "-fsanitize=address",
+        "-Wno-memset-transposed-args",
     ],
     // Ignore that we don't have ASAN symbols linked in.
     allow_undefined_symbols: true,
@@ -304,6 +305,7 @@
         "-Werror",
         "-D_FORTIFY_SOURCE=2",
         "-D__clang_analyzer__",
+        "-Wno-memset-transposed-args",
     ],
     srcs: ["fortify_filecheck_diagnostics_test.cpp"],
 }
diff --git a/tests/Android.mk b/tests/Android.mk
index fc7b940..848d291 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -65,18 +65,15 @@
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
-    $(LOCAL_PATH)/file-check-cxx \
-    | $(HOST_OUT_EXECUTABLES)/FileCheck$(HOST_EXECUTABLE_SUFFIX) \
+    $(LOCAL_PATH)/touch-obj-on-success
 
-LOCAL_CXX := $(LOCAL_PATH)/file-check-cxx \
-    $(HOST_OUT_EXECUTABLES)/FileCheck \
+LOCAL_CXX := $(LOCAL_PATH)/touch-obj-on-success \
     $(LLVM_PREBUILTS_PATH)/clang++ \
-    CLANG \
 
 LOCAL_CLANG := true
 LOCAL_MODULE := bionic-compile-time-tests-clang++
-LOCAL_CPPFLAGS := -Wall -Werror
-LOCAL_CPPFLAGS += -fno-color-diagnostics -ferror-limit=10000
+LOCAL_CPPFLAGS := -Wall -Wno-error
+LOCAL_CPPFLAGS += -fno-color-diagnostics -ferror-limit=10000 -Xclang -verify
 LOCAL_SRC_FILES := fortify_filecheck_diagnostics_test.cpp
 include $(BUILD_STATIC_LIBRARY)
 
diff --git a/tests/file-check-cxx b/tests/file-check-cxx
deleted file mode 100755
index d3bc5f7..0000000
--- a/tests/file-check-cxx
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-FILECHECK=$1
-CXX=$2
-PREFIX=$3
-shift 3
-SOURCE=$(echo "$@" | grep -oP '\S+\.cpp\b')
-OBJ=$(echo "$@" | grep -oP '\S+\.o\b')
-$CXX "$@" -Wno-error 2>&1 | $FILECHECK -check-prefix=$PREFIX $SOURCE
-if [ "$?" -eq 0 ]; then
-  touch $OBJ
-else
-  exit 1
-fi
diff --git a/tests/fortify_filecheck_diagnostics_test.cpp b/tests/fortify_filecheck_diagnostics_test.cpp
index e79a9a6..ac9853c 100644
--- a/tests/fortify_filecheck_diagnostics_test.cpp
+++ b/tests/fortify_filecheck_diagnostics_test.cpp
@@ -15,19 +15,14 @@
  */
 
 /*
- * If this test fails, you can see the compiler's output by erasing a few args from the failing
- * command. Specifically, delete everything before the path/to/the/compiler, then delete the first
- * arg after the path/to/the/compiler. For example, given the following command:
- *
- * bionic/tests/file-check-cxx out/host/linux-x86/bin/FileCheck \
- * prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ CLANG    -I bionic/tests -I ...
- *
- * If you delete everything before clang++ and delete "CLANG", then you'll end up with:
- *
- * prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ -I bionic/tests -I ...
- *
- * Which is the command that FileCheck executes.
+ * Silence all notes about enable_if-related 'candidates'; they're nice to know
+ * about for users, but this test doesn't care.
  */
+// expected-note@* 0+{{candidate function}}
+
+/* Similarly, ignore all "from 'diagnose_if'"s. */
+// expected-note@* 0+{{from 'diagnose_if'}}
+
 
 #undef _FORTIFY_SOURCE
 #define _FORTIFY_SOURCE 2
@@ -43,11 +38,15 @@
 #include <time.h>
 #include <unistd.h>
 
+#if !defined(__BIONIC__)
+#  error "This only works with Bionic."
+#endif
+
 void test_sprintf() {
   char buf[4];
 
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: call to unavailable function 'sprintf': format string will always overflow destination buffer
+  // expected-error@+1{{call to unavailable function 'sprintf': format string will always overflow destination buffer}}
   sprintf(buf, "foobar");  // NOLINT(runtime/printf)
 
   // TODO: clang should emit a warning, but doesn't
@@ -58,7 +57,7 @@
   char buf[4];
 
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: call to unavailable function 'snprintf': format string will always overflow destination buffer
+  // expected-error@+1{{call to unavailable function 'snprintf': format string will always overflow destination buffer}}
   snprintf(buf, 5, "foobar");  // NOLINT(runtime/printf)
 
   // TODO: clang should emit a warning, but doesn't
@@ -74,41 +73,41 @@
 void test_memcpy() {
   char buf[4];
 
-  // CLANG: error: 'memcpy' called with size bigger than buffer
+  // expected-error@+1{{'memcpy' called with size bigger than buffer}}
   memcpy(buf, "foobar", sizeof("foobar") + 100);
 }
 
 void test_memmove() {
   char buf[4];
 
-  // CLANG: error: 'memmove' called with size bigger than buffer
+  // expected-error@+1{{'memmove' called with size bigger than buffer}}
   memmove(buf, "foobar", sizeof("foobar"));
 }
 
 void test_memset() {
   char buf[4];
 
-  // CLANG: error: 'memset' called with size bigger than buffer
+  // expected-error@+1{{'memset' called with size bigger than buffer}}
   memset(buf, 0, 6);
 }
 
 void test_strcpy() {
   char buf[4];
 
-  // CLANG: error: 'strcpy' called with string bigger than buffer
+  // expected-error@+1{{'strcpy' called with string bigger than buffer}}
   strcpy(buf, "foobar");  // NOLINT(runtime/printf)
 
-  // CLANG: error: 'strcpy' called with string bigger than buffer
+  // expected-error@+1{{'strcpy' called with string bigger than buffer}}
   strcpy(buf, "quux");
 }
 
 void test_stpcpy() {
   char buf[4];
 
-  // CLANG: error: 'stpcpy' called with string bigger than buffer
+  // expected-error@+1{{'stpcpy' called with string bigger than buffer}}
   stpcpy(buf, "foobar");
 
-  // CLANG: error: 'stpcpy' called with string bigger than buffer
+  // expected-error@+1{{'stpcpy' called with string bigger than buffer}}
   stpcpy(buf, "quux");
 }
 
@@ -157,10 +156,10 @@
 void test_fgets() {
   char buf[4];
 
-  // CLANG: error: in call to 'fgets', size should not be negative
+  // expected-error@+1{{in call to 'fgets', size should not be negative}}
   fgets(buf, -1, stdin);
 
-  // CLANG: error: in call to 'fgets', size is larger than the destination buffer
+  // expected-error@+1{{in call to 'fgets', size is larger than the destination buffer}}
   fgets(buf, 6, stdin);
 }
 
@@ -168,58 +167,58 @@
   char buf[4];
   sockaddr_in addr;
 
-  // CLANG: error: 'recvfrom' called with size bigger than buffer
+  // expected-error@+1{{'recvfrom' called with size bigger than buffer}}
   recvfrom(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), nullptr);
 }
 
 void test_recv() {
   char buf[4] = {0};
 
-  // CLANG: error: 'recv' called with size bigger than buffer
+  // expected-error@+1{{'recv' called with size bigger than buffer}}
   recv(0, buf, 6, 0);
 }
 
 void test_umask() {
-  // CLANG: error: 'umask' called with invalid mode
+  // expected-error@+1{{'umask' called with invalid mode}}
   umask(01777);
 }
 
 void test_read() {
   char buf[4];
-  // CLANG: error: in call to 'read', 'count' bytes overflows the given object
+  // expected-error@+1{{in call to 'read', 'count' bytes overflows the given object}}
   read(0, buf, 6);
 }
 
 void test_open() {
-  // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
+  // expected-error@+1{{'open' called with O_CREAT or O_TMPFILE, but missing mode}}
   open("/dev/null", O_CREAT);
 
-  // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
+  // expected-error@+1{{'open' called with O_CREAT or O_TMPFILE, but missing mode}}
   open("/dev/null", O_TMPFILE);
 
-  // CLANG: error: call to unavailable function 'open': too many arguments
+  // expected-error@+1{{call to unavailable function 'open': too many arguments}}
   open("/dev/null", O_CREAT, 0, 0);
 
-  // CLANG: error: call to unavailable function 'open': too many arguments
+  // expected-error@+1{{call to unavailable function 'open': too many arguments}}
   open("/dev/null", O_TMPFILE, 0, 0);
 
-  // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
+  // expected-warning@+1{{'open' has superfluous mode bits; missing O_CREAT?}}
   open("/dev/null", O_RDONLY, 0644);
 
-  // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
+  // expected-warning@+1{{'open' has superfluous mode bits; missing O_CREAT?}}
   open("/dev/null", O_DIRECTORY, 0644);
 }
 
 void test_poll() {
   pollfd fds[1];
-  // CLANG: error: in call to 'poll', fd_count is larger than the given buffer
+  // expected-error@+1{{in call to 'poll', fd_count is larger than the given buffer}}
   poll(fds, 2, 0);
 }
 
 void test_ppoll() {
   pollfd fds[1];
   timespec timeout;
-  // CLANG: error: in call to 'ppoll', fd_count is larger than the given buffer
+  // expected-error@+1{{in call to 'ppoll', fd_count is larger than the given buffer}}
   ppoll(fds, 2, &timeout, nullptr);
 }
 
@@ -227,101 +226,98 @@
   pollfd fds[1];
   timespec timeout;
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: in call to 'ppoll64', fd_count is larger than the given buffer
+  // expected-error@+1{{in call to 'ppoll64', fd_count is larger than the given buffer}}
   ppoll64(fds, 2, &timeout, nullptr);
 }
 
 void test_fread_overflow() {
   char buf[4];
-  // CLANG: error: in call to 'fread', size * count overflows
+  // expected-error@+1{{in call to 'fread', size * count overflows}}
   fread(buf, 2, (size_t)-1, stdin);
 }
 
 void test_fread_too_big() {
   char buf[4];
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: in call to 'fread', size * count is too large for the given buffer
+  // expected-error@+1{{in call to 'fread', size * count is too large for the given buffer}}
   fread(buf, 1, 5, stdin);
 }
 
 void test_fwrite_overflow() {
   char buf[4] = {0};
-  // CLANG: error: in call to 'fwrite', size * count overflows
+  // expected-error@+1{{in call to 'fwrite', size * count overflows}}
   fwrite(buf, 2, (size_t)-1, stdout);
 }
 
 void test_fwrite_too_big() {
   char buf[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: in call to 'fwrite', size * count is too large for the given buffer
+  // expected-error@+1{{in call to 'fwrite', size * count is too large for the given buffer}}
   fwrite(buf, 1, 5, stdout);
 }
 
 void test_getcwd() {
   char buf[4];
-  // CLANG: error: in call to 'getcwd', 'size' bytes overflows the given object
+  // expected-error@+1{{in call to 'getcwd', 'size' bytes overflows the given object}}
   getcwd(buf, 5);
 }
 
 void test_pwrite64_size() {
   char buf[4] = {0};
-  // CLANG: error: in call to 'pwrite64', 'count' bytes overflows the given object
+  // expected-error@+1{{in call to 'pwrite64', 'count' bytes overflows the given object}}
   pwrite64(STDOUT_FILENO, buf, 5, 0);
 }
 
 void test_pwrite64_too_big_malloc() {
   void *buf = calloc(atoi("5"), 1);
-  // clang should emit a warning, but probably never will.
+  // expected-error@+1{{in call to 'pwrite64', 'count' must be <= SSIZE_MAX}}
   pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
 }
 
 void test_pwrite64_too_big() {
   char buf[4] = {0};
-  // CLANG: error: in call to 'pwrite64', 'count' must be <= SSIZE_MAX
+  // expected-error@+1{{in call to 'pwrite64', 'count' must be <= SSIZE_MAX}}
   pwrite64(STDOUT_FILENO, buf, SIZE_MAX, 0);
 }
 
 void test_write_size() {
   char buf[4] = {0};
-  // CLANG: error: in call to 'write', 'count' bytes overflows the given object
+  // expected-error@+1{{in call to 'write', 'count' bytes overflows the given object}}
   write(STDOUT_FILENO, buf, 5);
 }
 
 void test_memset_args_flipped() {
   char from[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: 'memset' will set 0 bytes; maybe the arguments got flipped?
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmemset-transposed-args"
+  // expected-warning@+1{{'memset' will set 0 bytes; maybe the arguments got flipped?}}
   memset(from, sizeof(from), 0);
-#pragma clang diagnostic pop
 }
 
 void test_sendto() {
   char buf[4] = {0};
   sockaddr_in addr;
 
-  // CLANG: error: 'sendto' called with size bigger than buffer
+  // expected-error@+1{{'sendto' called with size bigger than buffer}}
   sendto(0, buf, 6, 0, reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_in));
 }
 
 void test_send() {
   char buf[4] = {0};
 
-  // CLANG: error: 'send' called with size bigger than buffer
+  // expected-error@+1{{'send' called with size bigger than buffer}}
   send(0, buf, 6, 0);
 }
 
 void test_realpath() {
   char buf[4] = {0};
   // NOLINTNEXTLINE(whitespace/line_length)
-  // CLANG: error: 'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes
+  // expected-error@+1{{'realpath' output parameter must be NULL or a pointer to a buffer with >= PATH_MAX bytes}}
   realpath(".", buf);
 
   // This is fine.
   realpath(".", nullptr);
 
   char bigbuf[PATH_MAX];
-  // CLANG: error: 'realpath': NULL path is never correct; flipped arguments?
+  // expected-error@+1{{'realpath': NULL path is never correct; flipped arguments?}}
   realpath(nullptr, bigbuf);
 }
diff --git a/tests/touch-obj-on-success b/tests/touch-obj-on-success
new file mode 100755
index 0000000..df08a49
--- /dev/null
+++ b/tests/touch-obj-on-success
@@ -0,0 +1,8 @@
+#!/bin/bash -eu
+#
+# Runs the given C/C++ compile-ish command. On success, scrapes an object file
+# from that command line and touches it.
+
+"$@"
+obj="$(echo "$@" | grep -oP '\S+\.o\b')"
+touch "${obj}"