r239665 - Add `-verify-ignore-unexpected` option to ignore unexpected diagnostics in VerifyDiagnosticsConsumer

Eric Fiselier eric at efcs.ca
Sat Jun 13 00:11:40 PDT 2015


Author: ericwf
Date: Sat Jun 13 02:11:40 2015
New Revision: 239665

URL: http://llvm.org/viewvc/llvm-project?rev=239665&view=rev
Log:
Add `-verify-ignore-unexpected` option to ignore unexpected diagnostics in VerifyDiagnosticsConsumer

Summary:
The goal of this patch is to make `-verify` easier to use when testing libc++. The `notes` attached to compile error diagnostics are numerous and relatively unstable when they reference libc++ header internals. This patch allows libc++ to write stable compilation failure tests by allowing unexpected diagnostic messages to be ignored where they are not relevant.

This patch adds a new CC1 flag called `-verify-ignore-unexpected`. `-verify-ignore-unexpected` tells `VerifyDiagnosticsConsumer` to ignore *all* unexpected diagnostic messages. `-verify-ignore-unexpected=<LevelList>` can be used to only ignore certain diagnostic levels. `<LevelList>` is a comma separated list of diagnostic levels to ignore. The supported levels are `note`, `remark`, `warning` and `error`.



Reviewers: bogner, grosser, EricWF

Reviewed By: EricWF

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D10138

Added:
    cfe/trunk/lib/Basic/DiagnosticOptions.cpp
    cfe/trunk/test/Frontend/verify-ignore-unexpected.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticOptions.def
    cfe/trunk/include/clang/Basic/DiagnosticOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/lib/Basic/CMakeLists.txt
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Frontend/VerifyDiagnosticConsumer.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticOptions.def?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticOptions.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticOptions.def Sat Jun 13 02:11:40 2015
@@ -69,7 +69,10 @@ ENUM_DIAGOPT(ShowOverloads, OverloadsSho
 DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected
                                  /// diagnostics, indicated by markers in the
                                  /// input source file.
-
+ENUM_DIAGOPT(VerifyIgnoreUnexpected, DiagnosticLevelMask, 4,
+             DiagnosticLevelMask::None) /// Ignore unexpected diagnostics of
+                                        /// the specified levels when using
+                                        /// -verify.
 DIAGOPT(ElideType, 1, 0)         /// Elide identical types in template diffing
 DIAGOPT(ShowTemplateTree, 1, 0)  /// Print a template tree when diffing
 DIAGOPT(CLFallbackMode, 1, 0)    /// Format for clang-cl fallback mode

Modified: cfe/trunk/include/clang/Basic/DiagnosticOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticOptions.h?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticOptions.h (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticOptions.h Sat Jun 13 02:11:40 2015
@@ -13,6 +13,7 @@
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include <string>
+#include <type_traits>
 #include <vector>
 
 namespace clang {
@@ -24,6 +25,38 @@ enum OverloadsShown : unsigned {
   Ovl_Best  ///< Show just the "best" overload candidates.
 };
 
+/// \brief A bitmask representing the diagnostic levels used by
+/// VerifyDiagnosticConsumer.
+enum class DiagnosticLevelMask : unsigned {
+  None    = 0,
+  Note    = 1 << 0,
+  Remark  = 1 << 1,
+  Warning = 1 << 2,
+  Error   = 1 << 3,
+  All     = Note | Remark | Warning | Error
+};
+
+inline DiagnosticLevelMask operator~(DiagnosticLevelMask M) {
+  using UT = std::underlying_type<DiagnosticLevelMask>::type;
+  return static_cast<DiagnosticLevelMask>(~static_cast<UT>(M));
+}
+
+inline DiagnosticLevelMask operator|(DiagnosticLevelMask LHS,
+                                     DiagnosticLevelMask RHS) {
+  using UT = std::underlying_type<DiagnosticLevelMask>::type;
+  return static_cast<DiagnosticLevelMask>(
+    static_cast<UT>(LHS) | static_cast<UT>(RHS));
+}
+
+inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS,
+                                     DiagnosticLevelMask RHS) {
+  using UT = std::underlying_type<DiagnosticLevelMask>::type;
+  return static_cast<DiagnosticLevelMask>(
+    static_cast<UT>(LHS) & static_cast<UT>(RHS));
+}
+
+raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M);
+
 /// \brief Options for controlling the compiler diagnostics engine.
 class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
 public:

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Sat Jun 13 02:11:40 2015
@@ -301,6 +301,10 @@ def fmessage_length : Separate<["-"], "f
   HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
 def verify : Flag<["-"], "verify">,
   HelpText<"Verify diagnostic output using comment directives">;
+def verify_ignore_unexpected : Flag<["-"], "verify-ignore-unexpected">,
+  HelpText<"Ignore unexpected diagnostic messages">;
+def verify_ignore_unexpected_EQ : CommaJoined<["-"], "verify-ignore-unexpected=">,
+  HelpText<"Ignore unexpected diagnostic messages">;
 def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
   HelpText<"Silence ObjC rewriting warnings">;
 

Modified: cfe/trunk/lib/Basic/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/CMakeLists.txt?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/CMakeLists.txt (original)
+++ cfe/trunk/lib/Basic/CMakeLists.txt Sat Jun 13 02:11:40 2015
@@ -61,6 +61,7 @@ add_clang_library(clangBasic
   CharInfo.cpp
   Diagnostic.cpp
   DiagnosticIDs.cpp
+  DiagnosticOptions.cpp
   FileManager.cpp
   FileSystemStatCache.cpp
   IdentifierTable.cpp

Added: cfe/trunk/lib/Basic/DiagnosticOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticOptions.cpp?rev=239665&view=auto
==============================================================================
--- cfe/trunk/lib/Basic/DiagnosticOptions.cpp (added)
+++ cfe/trunk/lib/Basic/DiagnosticOptions.cpp Sat Jun 13 02:11:40 2015
@@ -0,0 +1,24 @@
+//===--- DiagnosticOptions.cpp - C Language Family Diagnostic Handling ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements the DiagnosticOptions related interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/DiagnosticOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M) {
+  using UT = std::underlying_type<DiagnosticLevelMask>::type;
+  return Out << static_cast<UT>(M);
+}
+
+} // end namespace clang

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Sat Jun 13 02:11:40 2015
@@ -321,6 +321,29 @@ GenerateOptimizationRemarkRegex(Diagnost
   return Pattern;
 }
 
+static bool parseDiagnosticLevelMask(StringRef FlagName,
+                                     const std::vector<std::string> &Levels,
+                                     DiagnosticsEngine *Diags,
+                                     DiagnosticLevelMask &M) {
+  bool Success = true;
+  for (const auto &Level : Levels) {
+    DiagnosticLevelMask const PM =
+      llvm::StringSwitch<DiagnosticLevelMask>(Level)
+        .Case("note",    DiagnosticLevelMask::Note)
+        .Case("remark",  DiagnosticLevelMask::Remark)
+        .Case("warning", DiagnosticLevelMask::Warning)
+        .Case("error",   DiagnosticLevelMask::Error)
+        .Default(DiagnosticLevelMask::None);
+    if (PM == DiagnosticLevelMask::None) {
+      Success = false;
+      if (Diags)
+        Diags->Report(diag::err_drv_invalid_value) << FlagName << Level;
+    }
+    M = M | PM;
+  }
+  return Success;
+}
+
 static void parseSanitizerKinds(StringRef FlagName,
                                 const std::vector<std::string> &Sanitizers,
                                 DiagnosticsEngine &Diags, SanitizerSet &S) {
@@ -748,11 +771,18 @@ bool clang::ParseDiagnosticArgs(Diagnost
       << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args)
       << Format;
   }
-  
+
   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);
+  DiagnosticLevelMask DiagMask = DiagnosticLevelMask::None;
+  Success &= parseDiagnosticLevelMask("-verify-ignore-unexpected=",
+    Args.getAllArgValues(OPT_verify_ignore_unexpected_EQ),
+    Diags, DiagMask);
+  if (Args.hasArg(OPT_verify_ignore_unexpected))
+    DiagMask = DiagnosticLevelMask::All;
+  Opts.setVerifyIgnoreUnexpected(DiagMask);
   Opts.ElideType = !Args.hasArg(OPT_fno_elide_type);
   Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree);
   Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags);

Modified: cfe/trunk/lib/Frontend/VerifyDiagnosticConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/VerifyDiagnosticConsumer.cpp?rev=239665&r1=239664&r2=239665&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/VerifyDiagnosticConsumer.cpp (original)
+++ cfe/trunk/lib/Frontend/VerifyDiagnosticConsumer.cpp Sat Jun 13 02:11:40 2015
@@ -691,7 +691,8 @@ static unsigned CheckLists(DiagnosticsEn
                            const char *Label,
                            DirectiveList &Left,
                            const_diag_iterator d2_begin,
-                           const_diag_iterator d2_end) {
+                           const_diag_iterator d2_end,
+                           bool IgnoreUnexpected) {
   std::vector<Directive *> LeftOnly;
   DiagList Right(d2_begin, d2_end);
 
@@ -727,7 +728,8 @@ static unsigned CheckLists(DiagnosticsEn
   }
   // Now all that's left in Right are those that were not matched.
   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
-  num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
+  if (!IgnoreUnexpected)
+    num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
   return num;
 }
 
@@ -745,21 +747,28 @@ static unsigned CheckResults(Diagnostics
   //   Seen \ Expected - set seen but not expected
   unsigned NumProblems = 0;
 
+  const DiagnosticLevelMask DiagMask =
+    Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
+
   // See if there are error mismatches.
   NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
-                            Buffer.err_begin(), Buffer.err_end());
+                            Buffer.err_begin(), Buffer.err_end(),
+                            bool(DiagnosticLevelMask::Error & DiagMask));
 
   // See if there are warning mismatches.
   NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
-                            Buffer.warn_begin(), Buffer.warn_end());
+                            Buffer.warn_begin(), Buffer.warn_end(),
+                            bool(DiagnosticLevelMask::Warning & DiagMask));
 
   // See if there are remark mismatches.
   NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
-                            Buffer.remark_begin(), Buffer.remark_end());
+                            Buffer.remark_begin(), Buffer.remark_end(),
+                            bool(DiagnosticLevelMask::Remark & DiagMask));
 
   // See if there are note mismatches.
   NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
-                            Buffer.note_begin(), Buffer.note_end());
+                            Buffer.note_begin(), Buffer.note_end(),
+                            bool(DiagnosticLevelMask::Note & DiagMask));
 
   return NumProblems;
 }
@@ -854,12 +863,20 @@ void VerifyDiagnosticConsumer::CheckDiag
     // Check that the expected diagnostics occurred.
     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
   } else {
-    NumErrors += (PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
-                                  Buffer->err_end(), "error") +
-                  PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
-                                  Buffer->warn_end(), "warn") +
-                  PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
-                                  Buffer->note_end(), "note"));
+    const DiagnosticLevelMask DiagMask =
+        ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
+    if (bool(DiagnosticLevelMask::Error & DiagMask))
+      NumErrors += PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
+                                   Buffer->err_end(), "error");
+    if (bool(DiagnosticLevelMask::Warning & DiagMask))
+      NumErrors += PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
+                                   Buffer->warn_end(), "warn");
+    if (bool(DiagnosticLevelMask::Remark & DiagMask))
+      NumErrors += PrintUnexpected(Diags, nullptr, Buffer->remark_begin(),
+                                   Buffer->remark_end(), "remark");
+    if (bool(DiagnosticLevelMask::Note & DiagMask))
+      NumErrors += PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
+                                   Buffer->note_end(), "note");
   }
 
   Diags.setClient(CurClient, Owner.release() != nullptr);

Added: cfe/trunk/test/Frontend/verify-ignore-unexpected.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Frontend/verify-ignore-unexpected.c?rev=239665&view=auto
==============================================================================
--- cfe/trunk/test/Frontend/verify-ignore-unexpected.c (added)
+++ cfe/trunk/test/Frontend/verify-ignore-unexpected.c Sat Jun 13 02:11:40 2015
@@ -0,0 +1,81 @@
+// RUN: not %clang_cc1 -DTEST_SWITCH -verify-ignore-unexpected=remark,aoeu,note -verify %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-BAD-SWITCH %s
+#ifdef TEST_SWITCH
+// expected-no-diagnostics
+#endif
+// CHECK-BAD-SWITCH: error: 'error' diagnostics seen but not expected:
+// CHECK-BAD-SWITCH-NEXT: (frontend): invalid value 'aoeu' in '-verify-ignore-unexpected='
+
+// RUN: %clang_cc1 -DTEST1 -verify %s
+// RUN: %clang_cc1 -DTEST1 -verify -verify-ignore-unexpected %s
+#ifdef TEST1
+#warning MyWarning1
+    // expected-warning at -1 {{MyWarning1}}
+int x; // expected-note {{previous definition is here}}
+float x; // expected-error {{redefinition of 'x'}}
+#endif
+
+// RUN: not %clang_cc1 -DTEST2 -verify %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-UNEXP %s
+// RUN: not %clang_cc1 -DTEST2 -verify -verify-ignore-unexpected= %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-UNEXP %s
+// RUN: not %clang_cc1 -DTEST2 -verify -verify-ignore-unexpected=note %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-NOTE %s
+// RUN: not %clang_cc1 -DTEST2 -verify -verify-ignore-unexpected=warning %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-WARN %s
+// RUN: not %clang_cc1 -DTEST2 -verify -verify-ignore-unexpected=error %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-ERR %s
+#ifdef TEST2
+#warning MyWarning2
+int x;
+float x;
+#endif
+// CHECK-UNEXP: no expected directives found
+// CHECK-UNEXP-NEXT: 'error' diagnostics seen but not expected
+// CHECK-UNEXP-NEXT: Line {{[0-9]+}}: redefinition of 'x'
+// CHECK-UNEXP-NEXT: 'warning' diagnostics seen but not expected
+// CHECK-UNEXP-NEXT: Line {{[0-9]+}}: MyWarning2
+// CHECK-UNEXP-NEXT: 'note' diagnostics seen but not expected
+// CHECK-UNEXP-NEXT: Line {{[0-9]+}}: previous definition is here
+// CHECK-UNEXP-NEXT: 4 errors generated.
+
+// CHECK-NOTE: no expected directives found
+// CHECK-NOTE-NEXT: 'error' diagnostics seen but not expected
+// CHECK-NOTE-NEXT: Line {{[0-9]+}}: redefinition of 'x'
+// CHECK-NOTE-NEXT: 'warning' diagnostics seen but not expected
+// CHECK-NOTE-NEXT: Line {{[0-9]+}}: MyWarning2
+// CHECK-NOTE-NEXT: 3 errors generated.
+
+// CHECK-WARN: no expected directives found
+// CHECK-WARN-NEXT: 'error' diagnostics seen but not expected
+// CHECK-WARN-NEXT: Line {{[0-9]+}}: redefinition of 'x'
+// CHECK-WARN-NEXT: 'note' diagnostics seen but not expected
+// CHECK-WARN-NEXT: Line {{[0-9]+}}: previous definition is here
+// CHECK-WARN-NEXT: 3 errors generated.
+
+// CHECK-ERR: no expected directives found
+// CHECK-ERR-NEXT: 'warning' diagnostics seen but not expected
+// CHECK-ERR-NEXT: Line {{[0-9]+}}: MyWarning2
+// CHECK-ERR-NEXT: 'note' diagnostics seen but not expected
+// CHECK-ERR-NEXT: Line {{[0-9]+}}: previous definition is here
+// CHECK-ERR-NEXT: 3 errors generated.
+
+// RUN: not %clang_cc1 -DTEST3 -verify -verify-ignore-unexpected %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-EXP %s
+#ifdef TEST3
+// expected-error {{test3}}
+#endif
+// CHECK-EXP: 'error' diagnostics expected but not seen
+// CHECK-EXP-NEXT: Line {{[0-9]+}}: test3
+
+// RUN: not %clang_cc1 -DTEST4 -verify -verify-ignore-unexpected %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-NOEXP %s
+// RUN: not %clang_cc1 -DTEST4 -verify -verify-ignore-unexpected=warning,error,note %s 2>&1 \
+// RUN:     | FileCheck -check-prefix=CHECK-NOEXP %s
+#ifdef TEST4
+#warning MyWarning4
+int x;
+float x;
+#endif
+// CHECK-NOEXP: error: no expected directives found
+// CHECK-NOEXP-NEXT: 1 error generated





More information about the cfe-commits mailing list