jdenny updated this revision to Diff 125223.
jdenny added a comment.

Rebased on master/trunk fetched today.


https://reviews.llvm.org/D39694

Files:
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Basic/DiagnosticOptions.h
  include/clang/Driver/CC1Options.td
  lib/Frontend/CompilerInvocation.cpp
  lib/Frontend/VerifyDiagnosticConsumer.cpp
  test/Frontend/verify-prefixes.c
  test/Sema/tautological-constant-compare.c
  test/Sema/tautological-constant-enum-compare.c
  test/Sema/tautological-unsigned-enum-zero-compare.c
  test/Sema/tautological-unsigned-enum-zero-compare.cpp
  test/Sema/tautological-unsigned-zero-compare.c

Index: test/Sema/tautological-unsigned-zero-compare.c
===================================================================
--- test/Sema/tautological-unsigned-zero-compare.c
+++ test/Sema/tautological-unsigned-zero-compare.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -DTEST -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify %s
-// RUN: %clang_cc1 -fsyntax-only -DTEST -verify -x c++ %s
-// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence %s
+// RUN: %clang_cc1 -fsyntax-only -verify -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence -x c++ %s
 
 unsigned uvalue(void);
 signed int svalue(void);
@@ -13,13 +13,8 @@
 void TFunc() {
   // Make sure that we do warn for normal variables in template functions !
   unsigned char c = svalue();
-#ifdef TEST
   if (c < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
       return;
-#else
-  if (c < 0)
-      return;
-#endif
 
   if (c < macro(0))
       return;
@@ -39,7 +34,8 @@
 
   unsigned un = uvalue();
 
-#ifdef TEST
+  // silence-no-diagnostics
+
   if (un == 0)
       return 0;
   if (un != 0)
@@ -91,65 +87,10 @@
       return 0;
   if (0UL >= un)
       return 0;
-#else
-// expected-no-diagnostics
-  if (un == 0)
-      return 0;
-  if (un != 0)
-      return 0;
-  if (un < 0)
-      return 0;
-  if (un <= 0)
-      return 0;
-  if (un > 0)
-      return 0;
-  if (un >= 0)
-      return 0;
-
-  if (0 == un)
-      return 0;
-  if (0 != un)
-      return 0;
-  if (0 < un)
-      return 0;
-  if (0 <= un)
-      return 0;
-  if (0 > un)
-      return 0;
-  if (0 >= un)
-      return 0;
-
-  if (un == 0UL)
-      return 0;
-  if (un != 0UL)
-      return 0;
-  if (un < 0UL)
-      return 0;
-  if (un <= 0UL)
-      return 0;
-  if (un > 0UL)
-      return 0;
-  if (un >= 0UL)
-      return 0;
-
-  if (0UL == un)
-      return 0;
-  if (0UL != un)
-      return 0;
-  if (0UL < un)
-      return 0;
-  if (0UL <= un)
-      return 0;
-  if (0UL > un)
-      return 0;
-  if (0UL >= un)
-      return 0;
-#endif
 
 
   signed int a = svalue();
 
-#ifdef TEST
   if (a == 0)
       return 0;
   if (a != 0)
@@ -201,60 +142,6 @@
       return 0;
   if (0UL >= a)
       return 0;
-#else
-// expected-no-diagnostics
-  if (a == 0)
-      return 0;
-  if (a != 0)
-      return 0;
-  if (a < 0)
-      return 0;
-  if (a <= 0)
-      return 0;
-  if (a > 0)
-      return 0;
-  if (a >= 0)
-      return 0;
-
-  if (0 == a)
-      return 0;
-  if (0 != a)
-      return 0;
-  if (0 < a)
-      return 0;
-  if (0 <= a)
-      return 0;
-  if (0 > a)
-      return 0;
-  if (0 >= a)
-      return 0;
-
-  if (a == 0UL)
-      return 0;
-  if (a != 0UL)
-      return 0;
-  if (a < 0UL)
-      return 0;
-  if (a <= 0UL)
-      return 0;
-  if (a > 0UL)
-      return 0;
-  if (a >= 0UL)
-      return 0;
-
-  if (0UL == a)
-      return 0;
-  if (0UL != a)
-      return 0;
-  if (0UL < a)
-      return 0;
-  if (0UL <= a)
-      return 0;
-  if (0UL > a)
-      return 0;
-  if (0UL >= a)
-      return 0;
-#endif
 
 
   float fl = 0;
Index: test/Sema/tautological-unsigned-enum-zero-compare.cpp
===================================================================
--- test/Sema/tautological-unsigned-enum-zero-compare.cpp
+++ test/Sema/tautological-unsigned-enum-zero-compare.cpp
@@ -1,6 +1,10 @@
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
-// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSILENCE -Wno-tautological-unsigned-enum-zero-compare -verify %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only \
+// RUN:            -verify=unsigned,unsigned-signed,expected %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -verify=unsigned-signed,signed-silence,expected %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -Wno-tautological-unsigned-enum-zero-compare \
+// RUN:            -verify=signed-silence,expected %s
 
 // Okay, this is where it gets complicated.
 // Then default enum sigdness is target-specific.
@@ -16,71 +20,70 @@
   enum C : signed { C_foo = 0, C_bar, };
   enum C c;
 
-#ifdef UNSIGNED
-  if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (a < 0) // unsigned-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
-  if (0 >= a)
+  if (0 >= a) // signed-silence-warning {{comparison 0 >= 'enum A' is always true}}
     return 0;
-  if (a > 0)
+  if (a > 0) // signed-silence-warning {{comparison 'enum A' > 0 is always false}}
     return 0;
-  if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+  if (0 <= a) // unsigned-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
-  if (a <= 0)
+  if (a <= 0) // signed-silence-warning {{comparison 'enum A' <= 0 is always true}}
     return 0;
-  if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+  if (0 > a) // unsigned-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  if (a >= 0) // unsigned-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
-  if (0 < a)
+  if (0 < a) // signed-silence-warning {{comparison 0 < 'enum A' is always false}}
     return 0;
 
-  if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (a < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0U >= a)
     return 0;
   if (a > 0U)
     return 0;
-  if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+  if (0U <= a) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (a <= 0U)
     return 0;
-  if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+  if (0U > a) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  if (a >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0U < a)
     return 0;
 
-  if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (b < 0) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0 >= b)
     return 0;
   if (b > 0)
     return 0;
-  if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+  if (0 <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (b <= 0)
     return 0;
-  if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+  if (0 > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  if (b >= 0) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0 < b)
     return 0;
 
-  if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (b < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0U >= b)
     return 0;
   if (b > 0U)
     return 0;
-  if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+  if (0U <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (b <= 0U)
     return 0;
-  if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+  if (0U > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  if (b >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0U < b)
     return 0;
@@ -102,227 +105,22 @@
   if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
     return 0;
 
-  if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  if (c < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0U >= c)
     return 0;
   if (c > 0U)
     return 0;
-  if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
+  if (0U <= c) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (c <= 0U)
     return 0;
-  if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
+  if (0U > c) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  if (c >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0U < c)
     return 0;
-#elif defined(SIGNED)
-  if (a < 0)
-    return 0;
-  if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}}
-    return 0;
-  if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}}
-    return 0;
-  if (0 <= a)
-    return 0;
-  if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}}
-    return 0;
-  if (0 > a)
-    return 0;
-  if (a >= 0)
-    return 0;
-  if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}}
-    return 0;
-
-  if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= a)
-    return 0;
-  if (a > 0U)
-    return 0;
-  if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (a <= 0U)
-    return 0;
-  if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < a)
-    return 0;
-
-  if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0 >= b)
-    return 0;
-  if (b > 0)
-    return 0;
-  if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (b <= 0)
-    return 0;
-  if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0 < b)
-    return 0;
-
-  if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= b)
-    return 0;
-  if (b > 0U)
-    return 0;
-  if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (b <= 0U)
-    return 0;
-  if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < b)
-    return 0;
-
-  if (c < 0)
-    return 0;
-  if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
-    return 0;
-  if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
-    return 0;
-  if (0 <= c)
-    return 0;
-  if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}}
-    return 0;
-  if (0 > c)
-    return 0;
-  if (c >= 0)
-    return 0;
-  if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
-    return 0;
-
-  if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= c)
-    return 0;
-  if (c > 0U)
-    return 0;
-  if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (c <= 0U)
-    return 0;
-  if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < c)
-    return 0;
-#else
-  if (a < 0)
-    return 0;
-  if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}}
-    return 0;
-  if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}}
-    return 0;
-  if (0 <= a)
-    return 0;
-  if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}}
-    return 0;
-  if (0 > a)
-    return 0;
-  if (a >= 0)
-    return 0;
-  if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}}
-    return 0;
-
-  if (a < 0U)
-    return 0;
-  if (0U >= a)
-    return 0;
-  if (a > 0U)
-    return 0;
-  if (0U <= a)
-    return 0;
-  if (a <= 0U)
-    return 0;
-  if (0U > a)
-    return 0;
-  if (a >= 0U)
-    return 0;
-  if (0U < a)
-    return 0;
-
-  if (b < 0)
-    return 0;
-  if (0 >= b)
-    return 0;
-  if (b > 0)
-    return 0;
-  if (0 <= b)
-    return 0;
-  if (b <= 0)
-    return 0;
-  if (0 > b)
-    return 0;
-  if (b >= 0)
-    return 0;
-  if (0 < b)
-    return 0;
-
-  if (b < 0U)
-    return 0;
-  if (0U >= b)
-    return 0;
-  if (b > 0U)
-    return 0;
-  if (0U <= b)
-    return 0;
-  if (b <= 0U)
-    return 0;
-  if (0U > b)
-    return 0;
-  if (b >= 0U)
-    return 0;
-  if (0U < b)
-    return 0;
-
-  if (c < 0)
-    return 0;
-  if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
-    return 0;
-  if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
-    return 0;
-  if (0 <= c)
-    return 0;
-  if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}}
-    return 0;
-  if (0 > c)
-    return 0;
-  if (c >= 0)
-    return 0;
-  if (0 < c) // expected-warning {{0 < 'enum C' is always false}}
-    return 0;
-
-  if (c < 0U)
-    return 0;
-  if (0U >= c)
-    return 0;
-  if (c > 0U)
-    return 0;
-  if (0U <= c)
-    return 0;
-  if (c <= 0U)
-    return 0;
-  if (0U > c)
-    return 0;
-  if (c >= 0U)
-    return 0;
-  if (0U < c)
-    return 0;
-#endif
 
   return 1;
 }
@@ -335,11 +133,7 @@
   enum A a;
 
   // used to crash in llvm::APSInt::getMaxValue()
-#ifndef SILENCE
-  if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-#else
-  if (a > 0)
-#endif
+  if (a < 0) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
 
   return 1;
Index: test/Sema/tautological-unsigned-enum-zero-compare.c
===================================================================
--- test/Sema/tautological-unsigned-enum-zero-compare.c
+++ test/Sema/tautological-unsigned-enum-zero-compare.c
@@ -1,6 +1,10 @@
-// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only \
+// RUN:            -verify=unsigned,unsigned-signed %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -verify=unsigned-signed %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -Wno-tautological-unsigned-enum-zero-compare \
+// RUN:            -verify=silence %s
 
 // Okay, this is where it gets complicated.
 // Then default enum sigdness is target-specific.
@@ -12,175 +16,38 @@
   enum B { B_a = -1 };
   enum B b;
 
-#ifdef UNSIGNED
-  if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0 >= a)
-    return 0;
-  if (a > 0)
-    return 0;
-  if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (a <= 0)
-    return 0;
-  if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0 < a)
-    return 0;
-
-  if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= a)
-    return 0;
-  if (a > 0U)
-    return 0;
-  if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (a <= 0U)
-    return 0;
-  if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < a)
-    return 0;
-
-  if (b < 0)
-    return 0;
-  if (0 >= b)
-    return 0;
-  if (b > 0)
-    return 0;
-  if (0 <= b)
-    return 0;
-  if (b <= 0)
-    return 0;
-  if (0 > b)
-    return 0;
-  if (b >= 0)
-    return 0;
-  if (0 < b)
-    return 0;
-
-  if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= b)
-    return 0;
-  if (b > 0U)
-    return 0;
-  if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (b <= 0U)
-    return 0;
-  if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < b)
-    return 0;
-#elif defined(SIGNED)
-  if (a < 0)
-    return 0;
-  if (0 >= a)
-    return 0;
-  if (a > 0)
-    return 0;
-  if (0 <= a)
-    return 0;
-  if (a <= 0)
-    return 0;
-  if (0 > a)
-    return 0;
-  if (a >= 0)
-    return 0;
-  if (0 < a)
-    return 0;
-
-  if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= a)
-    return 0;
-  if (a > 0U)
-    return 0;
-  if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (a <= 0U)
-    return 0;
-  if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < a)
-    return 0;
-
-  if (b < 0)
-    return 0;
-  if (0 >= b)
-    return 0;
-  if (b > 0)
-    return 0;
-  if (0 <= b)
-    return 0;
-  if (b <= 0)
-    return 0;
-  if (0 > b)
-    return 0;
-  if (b >= 0)
-    return 0;
-  if (0 < b)
-    return 0;
-
-  if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
-    return 0;
-  if (0U >= b)
-    return 0;
-  if (b > 0U)
-    return 0;
-  if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
-    return 0;
-  if (b <= 0U)
-    return 0;
-  if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
-    return 0;
-  if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
-    return 0;
-  if (0U < b)
-    return 0;
-#else
-  // expected-no-diagnostics
+  // silence-no-diagnostics
 
-  if (a < 0)
+  if (a < 0) // unsigned-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0 >= a)
     return 0;
   if (a > 0)
     return 0;
-  if (0 <= a)
+  if (0 <= a) // unsigned-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (a <= 0)
     return 0;
-  if (0 > a)
+  if (0 > a) // unsigned-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (a >= 0)
+  if (a >= 0) // unsigned-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0 < a)
     return 0;
 
-  if (a < 0U)
+  if (a < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0U >= a)
     return 0;
   if (a > 0U)
     return 0;
-  if (0U <= a)
+  if (0U <= a) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (a <= 0U)
     return 0;
-  if (0U > a)
+  if (0U > a) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (a >= 0U)
+  if (a >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0U < a)
     return 0;
@@ -202,23 +69,22 @@
   if (0 < b)
     return 0;
 
-  if (b < 0U)
+  if (b < 0U) // unsigned-signed-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0U >= b)
     return 0;
   if (b > 0U)
     return 0;
-  if (0U <= b)
+  if (0U <= b) // unsigned-signed-warning {{comparison of 0 <= unsigned enum expression is always true}}
     return 0;
   if (b <= 0U)
     return 0;
-  if (0U > b)
+  if (0U > b) // unsigned-signed-warning {{comparison of 0 > unsigned enum expression is always false}}
     return 0;
-  if (b >= 0U)
+  if (b >= 0U) // unsigned-signed-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
   if (0U < b)
     return 0;
-#endif
 
   if (a == 0)
     return 0;
Index: test/Sema/tautological-constant-enum-compare.c
===================================================================
--- test/Sema/tautological-constant-enum-compare.c
+++ test/Sema/tautological-constant-enum-compare.c
@@ -1,18 +1,15 @@
 // RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s
 // RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s
-// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s
+// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -Wno-tautological-constant-compare -verify=silence %s
+// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -Wno-tautological-constant-compare -verify=silence %s
 
 int main() {
   enum A { A_a = 2 };
   enum A a;
 
-#ifdef SILENCE
-  // expected-no-diagnostics
-#endif
+// silence-no-diagnostics
 
 #ifdef UNSIGNED
-#ifndef SILENCE
   if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
     return 0;
   if (0 >= a)
@@ -80,77 +77,7 @@
     return 0;
   if (4294967295U < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}}
     return 0;
-#else // SILENCE
-  if (a < 0)
-    return 0;
-  if (0 >= a)
-    return 0;
-  if (a > 0)
-    return 0;
-  if (0 <= a)
-    return 0;
-  if (a <= 0)
-    return 0;
-  if (0 > a)
-    return 0;
-  if (a >= 0)
-    return 0;
-  if (0 < a)
-    return 0;
-
-  if (a < 0U)
-    return 0;
-  if (0U >= a)
-    return 0;
-  if (a > 0U)
-    return 0;
-  if (0U <= a)
-    return 0;
-  if (a <= 0U)
-    return 0;
-  if (0U > a)
-    return 0;
-  if (a >= 0U)
-    return 0;
-  if (0U < a)
-    return 0;
-
-  if (a < 4294967295)
-    return 0;
-  if (4294967295 >= a)
-    return 0;
-  if (a > 4294967295)
-    return 0;
-  if (4294967295 <= a)
-    return 0;
-  if (a <= 4294967295)
-    return 0;
-  if (4294967295 > a)
-    return 0;
-  if (a >= 4294967295)
-    return 0;
-  if (4294967295 < a)
-    return 0;
-
-  if (a < 4294967295U)
-    return 0;
-  if (4294967295U >= a)
-    return 0;
-  if (a > 4294967295U)
-    return 0;
-  if (4294967295U <= a)
-    return 0;
-  if (a <= 4294967295U)
-    return 0;
-  if (4294967295U > a)
-    return 0;
-  if (a >= 4294967295U)
-    return 0;
-  if (4294967295U < a)
-    return 0;
-#endif
 #elif defined(SIGNED)
-#ifndef SILENCE
   if (a < -2147483648) // expected-warning {{comparison 'enum A' < -2147483648 is always false}}
     return 0;
   if (-2147483648 >= a)
@@ -201,58 +128,6 @@
     return 0;
   if (2147483647U < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}}
     return 0;
-#else // SILENCE
-  if (a < -2147483648)
-    return 0;
-  if (-2147483648 >= a)
-    return 0;
-  if (a > -2147483648)
-    return 0;
-  if (-2147483648 <= a)
-    return 0;
-  if (a <= -2147483648)
-    return 0;
-  if (-2147483648 > a)
-    return 0;
-  if (a >= -2147483648)
-    return 0;
-  if (-2147483648 < a)
-    return 0;
-
-  if (a < 2147483647)
-    return 0;
-  if (2147483647 >= a)
-    return 0;
-  if (a > 2147483647)
-    return 0;
-  if (2147483647 <= a)
-    return 0;
-  if (a <= 2147483647)
-    return 0;
-  if (2147483647 > a)
-    return 0;
-  if (a >= 2147483647)
-    return 0;
-  if (2147483647 < a)
-    return 0;
-
-  if (a < 2147483647U)
-    return 0;
-  if (2147483647U >= a)
-    return 0;
-  if (a > 2147483647U)
-    return 0;
-  if (2147483647U <= a)
-    return 0;
-  if (a <= 2147483647U)
-    return 0;
-  if (2147483647U > a)
-    return 0;
-  if (a >= 2147483647U)
-    return 0;
-  if (2147483647U < a)
-    return 0;
-#endif
 #endif
 
   return 1;
Index: test/Sema/tautological-constant-compare.c
===================================================================
--- test/Sema/tautological-constant-compare.c
+++ test/Sema/tautological-constant-compare.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify -x c++ %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify -x c++ %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify=silence %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -x c++ %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify=silence -x c++ %s
 
 int value(void);
 
@@ -12,13 +12,8 @@
 void TFunc() {
   // Make sure that we do warn for normal variables in template functions !
   unsigned char c = value();
-#ifdef TEST
   if (c > 255) // expected-warning {{comparison 'unsigned char' > 255 is always false}}
       return;
-#else
-  if (c > 255)
-      return;
-#endif
 
   if (c > macro(255))
       return;
@@ -40,7 +35,8 @@
 
   short s = value();
 
-#ifdef TEST
+  // silence-no-diagnostics
+
   if (s == 32767)
       return 0;
   if (s != 32767)
@@ -146,114 +142,6 @@
       return 0;
   if (-32768L >= s)
       return 0;
-#else
-  // expected-no-diagnostics
-  if (s == 32767)
-    return 0;
-  if (s != 32767)
-    return 0;
-  if (s < 32767)
-    return 0;
-  if (s <= 32767)
-    return 0;
-  if (s > 32767)
-    return 0;
-  if (s >= 32767)
-    return 0;
-
-  if (32767 == s)
-    return 0;
-  if (32767 != s)
-    return 0;
-  if (32767 < s)
-    return 0;
-  if (32767 <= s)
-    return 0;
-  if (32767 > s)
-    return 0;
-  if (32767 >= s)
-    return 0;
-
-  // FIXME: assumes two's complement
-  if (s == -32768)
-    return 0;
-  if (s != -32768)
-    return 0;
-  if (s < -32768)
-    return 0;
-  if (s <= -32768)
-    return 0;
-  if (s > -32768)
-    return 0;
-  if (s >= -32768)
-    return 0;
-
-  if (-32768 == s)
-    return 0;
-  if (-32768 != s)
-    return 0;
-  if (-32768 < s)
-    return 0;
-  if (-32768 <= s)
-    return 0;
-  if (-32768 > s)
-    return 0;
-  if (-32768 >= s)
-    return 0;
-
-  if (s == 32767UL)
-    return 0;
-  if (s != 32767UL)
-    return 0;
-  if (s < 32767UL)
-    return 0;
-  if (s <= 32767UL)
-    return 0;
-  if (s > 32767UL)
-    return 0;
-  if (s >= 32767UL)
-    return 0;
-
-  if (32767UL == s)
-    return 0;
-  if (32767UL != s)
-    return 0;
-  if (32767UL < s)
-    return 0;
-  if (32767UL <= s)
-    return 0;
-  if (32767UL > s)
-    return 0;
-  if (32767UL >= s)
-    return 0;
-
-  // FIXME: assumes two's complement
-  if (s == -32768L)
-    return 0;
-  if (s != -32768L)
-    return 0;
-  if (s < -32768L)
-    return 0;
-  if (s <= -32768L)
-    return 0;
-  if (s > -32768L)
-    return 0;
-  if (s >= -32768L)
-    return 0;
-
-  if (-32768L == s)
-    return 0;
-  if (-32768L != s)
-    return 0;
-  if (-32768L < s)
-    return 0;
-  if (-32768L <= s)
-    return 0;
-  if (-32768L > s)
-    return 0;
-  if (-32768L >= s)
-    return 0;
-#endif
 
   if (s == 0)
     return 0;
@@ -285,7 +173,6 @@
 
   unsigned short us = value();
 
-#ifdef TEST
   if (us == 65535)
       return 0;
   if (us != 65535)
@@ -337,60 +224,6 @@
       return 0;
   if (65535UL >= us) // expected-warning {{comparison 65535 >= 'unsigned short' is always true}}
       return 0;
-#else
-  // expected-no-diagnostics
-  if (us == 65535)
-      return 0;
-  if (us != 65535)
-      return 0;
-  if (us < 65535)
-      return 0;
-  if (us <= 65535)
-      return 0;
-  if (us > 65535)
-      return 0;
-  if (us >= 65535)
-      return 0;
-
-  if (65535 == us)
-      return 0;
-  if (65535 != us)
-      return 0;
-  if (65535 < us)
-      return 0;
-  if (65535 <= us)
-      return 0;
-  if (65535 > us)
-      return 0;
-  if (65535 >= us)
-      return 0;
-
-  if (us == 65535UL)
-      return 0;
-  if (us != 65535UL)
-      return 0;
-  if (us < 65535UL)
-      return 0;
-  if (us <= 65535UL)
-      return 0;
-  if (us > 65535UL)
-      return 0;
-  if (us >= 65535UL)
-      return 0;
-
-  if (65535UL == us)
-      return 0;
-  if (65535UL != us)
-      return 0;
-  if (65535UL < us)
-      return 0;
-  if (65535UL <= us)
-      return 0;
-  if (65535UL > us)
-      return 0;
-  if (65535UL >= us)
-      return 0;
-#endif
 
   if (us == 32767)
     return 0;
Index: test/Frontend/verify-prefixes.c
===================================================================
--- /dev/null
+++ test/Frontend/verify-prefixes.c
@@ -0,0 +1,139 @@
+#if GC
+# define GCONST const
+#else
+# define GCONST
+#endif
+
+// gconst-note@8 {{variable 'glb' declared const here}}
+GCONST int glb = 5;
+
+
+// Check various prefix spellings and combinations.  All -verify arguments
+// (without "=") together imply one -verify=expected argument.  Every prefix
+// must be unique throughout all implicit or explicit -verify=<prefixes>
+// arguments.
+//
+// RUN: %clang_cc1             -DGC           -verify=gconst                 %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC      -verify=lconst                 %s
+// RUN: %clang_cc1                       -DSC -verify=expected               %s
+// RUN: %clang_cc1                       -DSC -verify                        %s
+// RUN: %clang_cc1                       -DSC -verify -verify                %s
+// RUN: %clang_cc1                            -verify=nconst                 %s
+// RUN: %clang_cc1                            -verify=n-const                %s
+// RUN: %clang_cc1                            -verify=n_const                %s
+// RUN: %clang_cc1                            -verify=NConst                 %s
+// RUN: %clang_cc1                            -verify=NConst2                %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC      -verify=gconst,lconst          %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify=gconst,lconst,expected %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC      -verify=gconst -verify=lconst  %s
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify=gconst,lconst -verify  %s
+// RUN: %clang_cc1             -DGC      -DSC -verify -verify=gconst -verify %s
+//
+// Various tortured cases: multiple directives with different prefixes per
+// line, prefixes used as comments, prefixes prefixing prefixes, and prefixes
+// with special suffixes.
+// RUN: %clang_cc1 -Wcast-qual      -DLC      -verify=foo                    %s
+// RUN: %clang_cc1                       -DSC -verify=bar                    %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo,bar                %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=bar,foo                %s
+// RUN: %clang_cc1                       -DSC -verify=foo-bar                %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC      -verify=bar-foo                %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo,foo-bar            %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo-bar,foo            %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=bar,bar-foo            %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=bar-foo,bar            %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo-bar,bar-foo        %s
+// RUN: %clang_cc1                       -DSC -verify=foo-warning            %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC      -verify=bar-warning-re         %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo,foo-warning        %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=foo-warning,foo        %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=bar,bar-warning-re     %s
+// RUN: %clang_cc1 -Wcast-qual      -DLC -DSC -verify=bar-warning-re,bar     %s
+
+
+// Check invalid prefixes.  Make sure there's no additional output, which
+// might indicate that diagnostic verification became enabled even though it
+// was requested incorrectly.
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify=5abc %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-SPELL,ERR-HN %s < %t
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify='-xy' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-SPELL,ERR-HH %s < %t
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify='_k' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-SPELL,ERR-HU %s < %t
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify='#a' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-SPELL,ERR-HS %s < %t
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC -verify='b$' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-SPELL,ERR-BS %s < %t
+//
+// RUN: not %clang_cc1 -DSC -verify=foo,bar,foo %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-DUP-ALL,ERR-DUP-FOO %s < %t
+//
+// RUN: not %clang_cc1 -DSC -verify=foo -verify=foo,foo %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-DUP-ALL,ERR-DUP-FOO,ERR-DUP-FOO2 %s < %t
+//
+// RUN: not %clang_cc1 -DSC -verify=expected -verify=expected %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-DUP-ALL,ERR-DUP-EX %s < %t
+//
+// RUN: not %clang_cc1 -DSC -verify -verify=expected %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR-ALL,ERR-DUP-ALL,ERR-DUP-EX %s < %t
+//
+// ERR-ALL-NOT:       {{.}}
+// ERR-HN:            error: invalid value '5abc' in '-verify='
+// ERR-HH:            error: invalid value '-xy' in '-verify='
+// ERR-HU:            error: invalid value '_k' in '-verify='
+// ERR-HS:            error: invalid value '#a' in '-verify='
+// ERR-BS:            error: invalid value 'b$' in '-verify='
+// ERR-SPELL-NEXT:    note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-DUP-FOO:       error: invalid value 'foo' in '-verify='
+// ERR-DUP-EX:        error: invalid value 'expected' in '-verify='
+// ERR-DUP-FOO2-NEXT: error: invalid value 'foo' in '-verify='
+// ERR-DUP-FOO2-NEXT: note: -verify prefixes must be unique
+// ERR-DUP-ALL-NEXT:  note: -verify prefixes must be unique
+// ERR-ALL-NOT:       {{.}}
+
+
+// Check that our test code actually has expected diagnostics when there's no
+// -verify.
+//
+// RUN: not %clang_cc1 -Wcast-qual -DGC -DLC -DSC %s 2> %t
+// RUN: FileCheck --check-prefix=ALL %s < %t
+//
+// ALL: cannot assign to variable 'glb' with const-qualified type 'const int'
+// ALL: variable 'glb' declared const here
+// ALL: cast from 'const int *' to 'int *' drops const qualifier
+// ALL: initializing 'int *' with an expression of type 'const int *' discards qualifiers
+
+
+#if LC
+# define LCONST const
+#else
+# define LCONST
+#endif
+
+#if SC
+# define SCONST const
+#else
+# define SCONST
+#endif
+
+void foo() {
+  LCONST int loc = 5;
+  SCONST static int sta = 5;
+  // We don't actually expect 1-2 occurrences of this error.  We're just
+  // checking the parsing.
+  glb = 6; // gconst-error1-2 {{cannot assign to variable 'glb' with const-qualified type 'const int'}}
+  *(int*)(&loc) = 6; // lconst-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+  ; // Code, comments, and many directives with different prefixes per line, including cases where some prefixes (foo and bar) prefix others (such as foo-bar and bar-foo), such that some prefixes appear as normal comments and some have special suffixes (-warning and -re): foo-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} foo-bar-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} foo-warning-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}} bar-warning-re-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} bar-foo-warning@-1 {{cast from 'const int *' to 'int *' drops const qualifier}} bar-warning@+1 {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+  int *p = &sta; // expected-warning {{initializing 'int *' with an expression of type 'const int *' discards qualifiers}}
+}
+
+// nconst-no-diagnostics
+// n-const-no-diagnostics
+// n_const-no-diagnostics
+// NConst-no-diagnostics
+// NConst2-no-diagnostics
Index: lib/Frontend/VerifyDiagnosticConsumer.cpp
===================================================================
--- lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -231,20 +231,43 @@
 
   // Return true if string literal is found.
   // When true, P marks begin-position of S in content.
-  bool Search(StringRef S, bool EnsureStartOfWord = false) {
+  bool Search(StringRef S, bool EnsureStartOfWord = false,
+              bool FinishDirectiveWord = false) {
     do {
-      P = std::search(C, End, S.begin(), S.end());
-      PEnd = P + S.size();
+      if (!S.empty()) {
+        P = std::search(C, End, S.begin(), S.end());
+        PEnd = P + S.size();
+      }
+      else {
+        P = C;
+        while (P != End && !isLetter(*P))
+          ++P;
+        PEnd = P + 1;
+      }
       if (P == End)
         break;
-      if (!EnsureStartOfWord
-            // Check if string literal starts a new word.
-            || P == Begin || isWhitespace(P[-1])
-            // Or it could be preceded by the start of a comment.
-            || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
-                                &&  P[-2] == '/'))
-        return true;
-      // Otherwise, skip and search again.
+      // If not start of word but required, skip and search again.
+      if (EnsureStartOfWord
+               // Check if string literal starts a new word.
+          && !(P == Begin || isWhitespace(P[-1])
+               // Or it could be preceded by the start of a comment.
+               || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
+                                   &&  P[-2] == '/')))
+        continue;
+      if (FinishDirectiveWord) {
+        while (PEnd != End && (isAlphanumeric(*PEnd)
+                               || *PEnd == '-' || *PEnd == '_'))
+          ++PEnd;
+        // Put back trailing digits and hyphens to be parsed later as a count
+        // or count range.  Because -verify prefixes must start with letters,
+        // we know the actual directive we found starts with a letter, so
+        // we won't put back the entire directive word and thus record an empty
+        // string.
+        assert(isLetter(*P) && "-verify prefix must start with a letter");
+        while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
+          --PEnd;
+      }
+      return true;
     } while (Advance());
     return false;
   }
@@ -314,37 +337,70 @@
   // A single comment may contain multiple directives.
   bool FoundDirective = false;
   for (ParseHelper PH(S); !PH.Done();) {
-    // Search for token: expected
-    if (!PH.Search("expected", true))
+    // Search for the initial directive token.
+    // If one prefix, save time by searching only for its directives.
+    // Otherwise, search for any potential directive token and check it later.
+    const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
+    if (!(Prefixes.size() == 1 ? PH.Search(Prefixes[0], true, true)
+                               : PH.Search("", true, true)))
       break;
     PH.Advance();
 
-    // Next token: -
-    if (!PH.Next("-"))
-      continue;
-    PH.Advance();
+    // Default directive kind.
+    bool RegexKind = false;
+    const char* KindStr = "string";
+
+    // Parse the initial directive token in reverse so we can easily determine
+    // its exact actual prefix.  If we were to parse it from the front instead,
+    // it would be harder to determine where the prefix ends because there
+    // might be multiple matching -verify prefixes because some might prefix
+    // others.
+    StringRef DToken(PH.P, PH.C - PH.P);
 
-    // Next token: { error | warning | note }
+    // Regex in initial directive token: -re
+    if (DToken.endswith("-re")) {
+      RegexKind = true;
+      KindStr = "regex";
+      DToken = DToken.substr(0, DToken.size()-3);
+    }
+
+    // Type in initial directive token: -{error|warning|note|no-diagnostics}
     DirectiveList *DL = nullptr;
-    if (PH.Next("error"))
-      DL = ED ? &ED->Errors : nullptr;
-    else if (PH.Next("warning"))
-      DL = ED ? &ED->Warnings : nullptr;
-    else if (PH.Next("remark"))
-      DL = ED ? &ED->Remarks : nullptr;
-    else if (PH.Next("note"))
-      DL = ED ? &ED->Notes : nullptr;
-    else if (PH.Next("no-diagnostics")) {
+    bool NoDiag = false;
+    {
+      StringRef DType;
+      if (DToken.endswith(DType="-error"))
+        DL = ED ? &ED->Errors : nullptr;
+      else if (DToken.endswith(DType="-warning"))
+        DL = ED ? &ED->Warnings : nullptr;
+      else if (DToken.endswith(DType="-remark"))
+        DL = ED ? &ED->Remarks : nullptr;
+      else if (DToken.endswith(DType="-note"))
+        DL = ED ? &ED->Notes : nullptr;
+      else if (DToken.endswith(DType="-no-diagnostics")) {
+        NoDiag = true;
+        if (RegexKind)
+          continue;
+      }
+      else
+        continue;
+      DToken = DToken.substr(0, DToken.size()-DType.size());
+    }
+
+    // What's left in DToken is the actual prefix.  That might not be a -verify
+    // prefix even if there is only one -verify prefix (for example, the full
+    // DToken is foo-bar-warning, but foo is the only -verify prefix).
+    if (Prefixes.end() == std::find(Prefixes.begin(), Prefixes.end(), DToken))
+      continue;
+
+    if (NoDiag) {
       if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
         Diags.Report(Pos, diag::err_verify_invalid_no_diags)
           << /*IsExpectedNoDiagnostics=*/true;
       else
         Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
       continue;
-    } else
-      continue;
-    PH.Advance();
-
+    }
     if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
       Diags.Report(Pos, diag::err_verify_invalid_no_diags)
         << /*IsExpectedNoDiagnostics=*/false;
@@ -357,17 +413,6 @@
     if (!DL)
       return true;
 
-    // Default directive kind.
-    bool RegexKind = false;
-    const char* KindStr = "string";
-
-    // Next optional token: -
-    if (PH.Next("-re")) {
-      PH.Advance();
-      RegexKind = true;
-      KindStr = "regex";
-    }
-
     // Next optional token: @
     SourceLocation ExpectedLoc;
     bool MatchAnyLine = false;
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1069,6 +1069,41 @@
           llvm::sys::Process::StandardErrHasColors());
 }
 
+static bool checkVerifyPrefixes(DiagnosticOptions &Opts,
+                                DiagnosticsEngine *Diags) {
+  bool Success = true;
+  std::set<std::string> PrefixSet;
+  for (const auto &Prefix : Opts.VerifyPrefixes) {
+    // Every prefix must start with a letter and contain only alphanumeric
+    // characters, hyphens, and underscores.
+    auto BadChar = std::find_if(Prefix.begin(), Prefix.end(),
+                                [](char C){return !isAlphanumeric(C)
+                                                  && C!='-' && C!='_';});
+    if (BadChar != Prefix.end() || !isLetter(Prefix[0])) {
+      Success = false;
+      if (Diags) {
+        Diags->Report(diag::err_drv_invalid_value) << "-verify=" << Prefix;
+        Diags->Report(diag::note_drv_verify_prefix_spelling);
+      }
+      continue;
+    }
+    // Every prefix must be unique throughout all implicit or explicit
+    // -verify=<prefixes> arguments.
+    if (PrefixSet.count(Prefix)) {
+      Success = false;
+      if (Diags) {
+        Diags->Report(diag::err_drv_invalid_value) << "-verify=" << Prefix;
+        Diags->Report(diag::note_drv_verify_prefix_unique);
+      }
+      continue;
+    }
+    PrefixSet.insert(Prefix);
+  }
+  if (!Success)
+    Opts.VerifyDiagnostics = false;
+  return Success;
+}
+
 bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                 DiagnosticsEngine *Diags,
                                 bool DefaultDiagColor, bool DefaultShowOpt) {
@@ -1156,7 +1191,12 @@
   Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
   Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
   Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location);
-  Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+  Opts.VerifyDiagnostics = Args.hasArg(OPT_verify) || Args.hasArg(OPT_verify_EQ);
+  Opts.VerifyPrefixes = Args.getAllArgValues(OPT_verify_EQ);
+  // All -verify arguments together imply one -verify=expected argument.
+  if (Args.hasArg(OPT_verify))
+    Opts.VerifyPrefixes.push_back("expected");
+  Success &= checkVerifyPrefixes(Opts, Diags);
   DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
   Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=",
     Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ),
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -400,8 +400,11 @@
   HelpText<"Set the maximum number of source lines to show in a caret diagnostic">;
 def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
   HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
+def verify_EQ : CommaJoined<["-"], "verify=">,
+  MetaVarName<"<prefixes>">,
+  HelpText<"Verify diagnostic output using comment directives that start with prefixes in the comma-separated sequence <prefixes>">;
 def verify : Flag<["-"], "verify">,
-  HelpText<"Verify diagnostic output using comment directives">;
+  HelpText<"Similar to -verify=expected">;
 def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
   HelpText<"Ignore unexpected diagnostic messages">;
 def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
Index: include/clang/Basic/DiagnosticOptions.h
===================================================================
--- include/clang/Basic/DiagnosticOptions.h
+++ include/clang/Basic/DiagnosticOptions.h
@@ -100,6 +100,10 @@
   /// prefixes removed.
   std::vector<std::string> Remarks;
 
+  /// The prefixes for comment directives sought by -verify ("expected" by
+  /// default).
+  std::vector<std::string> VerifyPrefixes;
+
 public:
   // Define accessors/mutators for diagnostic options of enumeration type.
 #define DIAGOPT(Name, Bits, Default)
Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td
+++ include/clang/Basic/DiagnosticDriverKinds.td
@@ -338,4 +338,7 @@
 def warn_drv_fine_grained_bitfield_accesses_ignored : Warning<
   "option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored">,
   InGroup<OptionIgnored>;
+
+def note_drv_verify_prefix_spelling : Note<"-verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores">;
+def note_drv_verify_prefix_unique : Note<"-verify prefixes must be unique">;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to