]> granicus.if.org Git - clang/commitdiff
[VerifyDiagnosticConsumer] support -verify=<prefixes>
authorHal Finkel <hfinkel@anl.gov>
Sat, 16 Dec 2017 02:23:22 +0000 (02:23 +0000)
committerHal Finkel <hfinkel@anl.gov>
Sat, 16 Dec 2017 02:23:22 +0000 (02:23 +0000)
This mimics FileCheck's --check-prefixes option.

The default prefix is "expected". That is, "-verify" is equivalent to
"-verify=expected".

The goal is to permit exercising a single test suite source file with different
compiler options producing different sets of diagnostics.  While cpp can be
combined with the existing -verify to accomplish the same goal, source is often
easier to maintain when it's not cluttered with preprocessor directives or
duplicate passages of code. For example, this patch also rewrites some existing
clang tests to demonstrate the benefit of this feature.

Patch by Joel E. Denny, thanks!

Differential Revision: https://reviews.llvm.org/D39694

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320908 91177308-0d34-0410-b5e6-96231b3b80d8

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/diagnostics-order.c
test/Frontend/verify-prefixes.c [new file with mode: 0644]
test/Sema/tautological-unsigned-enum-zero-compare.c
test/Sema/tautological-unsigned-enum-zero-compare.cpp
test/Sema/tautological-unsigned-zero-compare.c

index dd72c958d131d8654f683224ea68f2aea84a9b77..41b5e42b4432219ceb25896c729ee1ec57cbb22f 100644 (file)
@@ -338,4 +338,8 @@ def warn_drv_msvc_not_found : Warning<
 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">;
 }
index c195003de5c459645098bc71d374b28f6bf25293..3844eb63f0eaf095256bbb4dc48c77aa11f34072 100644 (file)
@@ -100,6 +100,10 @@ public:
   /// 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 c81fbfd9d5c4cbf1c8169fe64596886259f9144d..026f0162d750b34ff41e7da23d3985a00a48b85f 100644 (file)
@@ -400,8 +400,12 @@ def fcaret_diagnostics_max_lines :
   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<"Equivalent 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 be907d9ba858fb354fae3f0c88a1ff10c75268ae..9fabcdf05a8d83642d466f279a60b458a80eb4c8 100644 (file)
@@ -1071,6 +1071,26 @@ static bool parseShowColorsArgs(const ArgList &Args, bool DefaultColor) {
           llvm::sys::Process::StandardErrHasColors());
 }
 
+static bool checkVerifyPrefixes(const std::vector<std::string> &VerifyPrefixes,
+                                DiagnosticsEngine *Diags) {
+  bool Success = true;
+  for (const auto &Prefix : 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);
+      }
+    }
+  }
+  return Success;
+}
+
 bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                 DiagnosticsEngine *Diags,
                                 bool DefaultDiagColor, bool DefaultShowOpt) {
@@ -1158,7 +1178,18 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
   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);
+  if (Args.hasArg(OPT_verify))
+    Opts.VerifyPrefixes.push_back("expected");
+  // Keep VerifyPrefixes in its original order for the sake of diagnostics, and
+  // then sort it to prepare for fast lookup using std::binary_search.
+  if (!checkVerifyPrefixes(Opts.VerifyPrefixes, Diags)) {
+    Opts.VerifyDiagnostics = false;
+    Success = false;
+  }
+  else
+    std::sort(Opts.VerifyPrefixes.begin(), Opts.VerifyPrefixes.end());
   DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
   Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=",
     Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ),
index a49c424e915fa143fbcd17f7701ca2aa546c44db..0df5393a309bfa5cf181498c4130dcba4c3d6592 100644 (file)
@@ -229,22 +229,52 @@ public:
     return true;
   }
 
-  // Return true if string literal is found.
-  // When true, P marks begin-position of S in content.
-  bool Search(StringRef S, bool EnsureStartOfWord = false) {
+  // Return true if string literal S is matched in content.
+  // When true, P marks begin-position of the match, and calling Advance sets C
+  // to end-position of the match.
+  // If S is the empty string, then search for any letter instead (makes sense
+  // with FinishDirectiveToken=true).
+  // If EnsureStartOfWord, then skip matches that don't start a new word.
+  // If FinishDirectiveToken, then assume the match is the start of a comment
+  // directive for -verify, and extend the match to include the entire first
+  // token of that directive.
+  bool Search(StringRef S, bool EnsureStartOfWord = false,
+              bool FinishDirectiveToken = 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 (FinishDirectiveToken) {
+        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 +344,68 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
   // 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.begin(), 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"))
+    bool NoDiag = false;
+    StringRef DType;
+    if (DToken.endswith(DType="-error"))
       DL = ED ? &ED->Errors : nullptr;
-    else if (PH.Next("warning"))
+    else if (DToken.endswith(DType="-warning"))
       DL = ED ? &ED->Warnings : nullptr;
-    else if (PH.Next("remark"))
+    else if (DToken.endswith(DType="-remark"))
       DL = ED ? &ED->Remarks : nullptr;
-    else if (PH.Next("note"))
+    else if (DToken.endswith(DType="-note"))
       DL = ED ? &ED->Notes : nullptr;
-    else if (PH.Next("no-diagnostics")) {
+    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 (!std::binary_search(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 +418,6 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
     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 e557fc631ded37383f2f6116e5aaa73329980bd2..37c0cd90d15cca5ed53b86aff08e8b5cce8ed225 100644 (file)
@@ -2,9 +2,11 @@
 // Previously, these diagnostics were grouped by diagnostic level with all
 // notes last.
 //
-// RUN: not %clang_cc1 -O999 -std=bogus %s 2> %t
+// RUN: not %clang_cc1 -O999 -std=bogus -verify=-foo %s 2> %t
 // RUN: FileCheck < %t %s
 //
-// CHECK: warning: optimization level '-O999' is not supported
+// CHECK:      error: invalid value '-foo' in '-verify='
+// CHECK-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// CHECK-NEXT: warning: optimization level '-O999' is not supported
 // CHECK-NEXT: error: invalid value 'bogus' in '-std=bogus'
 // CHECK-NEXT: note: use {{.*}} for {{.*}} standard
diff --git a/test/Frontend/verify-prefixes.c b/test/Frontend/verify-prefixes.c
new file mode 100644 (file)
index 0000000..c5b545c
--- /dev/null
@@ -0,0 +1,118 @@
+#if GC
+# define GCONST const
+#else
+# define GCONST
+#endif
+
+// gconst-note@8 {{variable 'glb' declared const here}}
+GCONST int glb = 5;
+
+
+// Check various correct prefix spellings and combinations.
+//
+// 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
+//
+// Duplicate prefixes.
+// RUN: %clang_cc1 -Wcast-qual -DGC -DLC      -verify=gconst,lconst,gconst         %s
+// RUN: %clang_cc1             -DGC           -verify=gconst -verify=gconst,gconst %s
+// RUN: %clang_cc1                       -DSC -verify=expected -verify=expected    %s
+// RUN: %clang_cc1                       -DSC -verify -verify=expected             %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.  Check that there's no additional output, which
+// might indicate that diagnostic verification became enabled even though it
+// was requested incorrectly.  Check that prefixes are reported in command-line
+// order.
+//
+// RUN: not %clang_cc1 -verify=5abc,-xy,foo,_k -verify='#a,b$' %s 2> %t
+// RUN: FileCheck --check-prefixes=ERR %s < %t
+//
+// ERR-NOT:  {{.}}
+// ERR:      error: invalid value '5abc' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '-xy' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '_k' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value '#a' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-NEXT: error: invalid value 'b$' in '-verify='
+// ERR-NEXT: note: -verify prefixes must start with a letter and contain only alphanumeric characters, hyphens, and underscores
+// ERR-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 43b768433dbf96943f21a6f10e3c6a34f246db52..a32cfcd8329f21a6f4a5b63882e72597648a33d4 100644 (file)
@@ -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 @@ int main() {
   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 @@ int main() {
   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 5577b68b5ebd52201ea9ac7acb80f67a478bc737..a733b6edfc03427ca1469ea38738cefab84497ed 100644 (file)
@@ -1,6 +1,12 @@
-// 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 %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -verify=unsigned-signed %s
+// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
+// RUN:            -Wno-tautological-unsigned-enum-zero-compare \
+// RUN:            -verify=silence %s
+
+// silence-no-diagnostics
 
 int main() {
   // On Windows, all enumerations have a fixed underlying type, which is 'int'
@@ -16,71 +22,72 @@ int main() {
   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)
     return 0;
   if (a > 0)
     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)
     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)
     return 0;
 
-  if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
+  // FIXME: As below, the issue here is that the enumeration is promoted to
+  // unsigned.
+  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;
@@ -104,230 +111,22 @@ int main() {
 
   // FIXME: These diagnostics are terrible. The issue here is that the signed
   // enumeration value was promoted to an unsigned type.
-  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;
-#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;
-
-  // FIXME: As above, the issue here is that the enumeration is promoted to
-  // unsigned.
-  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)
-    return 0;
-  if (c > 0)
-    return 0;
-  if (0 <= c)
-    return 0;
-  if (c <= 0)
-    return 0;
-  if (0 > c)
-    return 0;
-  if (c >= 0)
-    return 0;
-  if (0 < c)
-    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;
-#else
-  // expected-no-diagnostics
-  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 (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)
-    return 0;
-  if (c > 0)
-    return 0;
-  if (0 <= c)
-    return 0;
-  if (c <= 0)
-    return 0;
-  if (0 > c)
-    return 0;
-  if (c >= 0)
-    return 0;
-  if (0 < 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;
-  if (c >= 0U)
-    return 0;
-  if (0U < c)
-    return 0;
-#endif
 
   return 1;
 }
@@ -340,11 +139,7 @@ int test() {
   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 e0611cb400294822a38804a9b5e8ec9237d2c2ce..b9ea02a731a3edaee90079b39a6f74b9a38132c9 100644 (file)
@@ -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 @@ template<typename T>
 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 @@ int main()
 
   unsigned un = uvalue();
 
-#ifdef TEST
+  // silence-no-diagnostics
+
   if (un == 0)
       return 0;
   if (un != 0)
@@ -91,65 +87,10 @@ int main()
       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 @@ int main()
       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;