Emit -verify diagnostics even when we have a fatal error.

Previously we'd halt at the fatal error as expected, but not actually emit
any -verify-related diagnostics. This lets us catch cases that emit a
/different/ fatal error from the one we expected.

This is implemented by adding a "force emit" mode to DiagnosticBuilder, which
will cause diagnostics to immediately be emitted regardless of current
suppression. Needless to say this should probably be used /very/ sparingly.

Patch by Andy Gibbs! Tests for all of Andy's -verify patches coming soon.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160053 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 7e2227b..8b4d3a0 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -763,7 +763,9 @@
   friend class Sema;
 
   /// \brief Emit the current diagnostic and clear the diagnostic state.
-  bool EmitCurrentDiagnostic();
+  ///
+  /// \param Force Emit the diagnostic regardless of suppression settings.
+  bool EmitCurrentDiagnostic(bool Force = false);
 
   unsigned getCurrentDiagID() const { return CurDiagID; }
 
@@ -833,14 +835,20 @@
   // Emit() would end up with if we used that as our status variable.
   mutable bool IsActive;
 
+  /// \brief Flag indicating that this diagnostic is being emitted via a
+  /// call to ForceEmit.
+  mutable bool IsForceEmit;
+
   void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT
   friend class DiagnosticsEngine;
   
   DiagnosticBuilder()
-    : DiagObj(0), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(false) { }
+    : DiagObj(0), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(false),
+      IsForceEmit(false) { }
 
   explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
-    : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(true) {
+    : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(true),
+      IsForceEmit(false) {
     assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
   }
 
@@ -857,6 +865,7 @@
   void Clear() const {
     DiagObj = 0;
     IsActive = false;
+    IsForceEmit = false;
   }
 
   /// \brief Determine whether this diagnostic is still active.
@@ -879,7 +888,7 @@
     FlushCounts();
 
     // Process the diagnostic.
-    bool Result = DiagObj->EmitCurrentDiagnostic();
+    bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
 
     // This diagnostic is dead.
     Clear();
@@ -893,6 +902,7 @@
   DiagnosticBuilder(const DiagnosticBuilder &D) {
     DiagObj = D.DiagObj;
     IsActive = D.IsActive;
+    IsForceEmit = D.IsForceEmit;
     D.Clear();
     NumArgs = D.NumArgs;
     NumRanges = D.NumRanges;
@@ -909,6 +919,12 @@
     Emit();
   }
   
+  /// \brief Forces the diagnostic to be emitted.
+  const DiagnosticBuilder &setForceEmit() const {
+    IsForceEmit = true;
+    return *this;
+  }
+
   /// \brief Conversion of DiagnosticBuilder to bool always returns \c true.
   ///
   /// This allows is to be used in boolean error contexts (where \c true is
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 3642da1..148a14e 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -268,6 +268,10 @@
   /// suppressed.
   bool ProcessDiag(DiagnosticsEngine &Diag) const;
 
+  /// \brief Used to emit a diagnostic that is finally fully formed,
+  /// ignoring suppression.
+  void EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const;
+
   /// \brief Whether the diagnostic may leave the AST in a state where some
   /// invariants can break.
   bool isUnrecoverable(unsigned DiagID) const;
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index fdc37b6..6e79b85 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -382,17 +382,34 @@
   CurDiagID = ~0U;
 }
 
-bool DiagnosticsEngine::EmitCurrentDiagnostic() {
-  // Process the diagnostic, sending the accumulated information to the
-  // DiagnosticConsumer.
-  bool Emitted = ProcessDiag();
+bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
+  assert(getClient() && "DiagnosticClient not set!");
+
+  bool Emitted;
+  if (Force) {
+    Diagnostic Info(this);
+
+    // Figure out the diagnostic level of this message.
+    DiagnosticIDs::Level DiagLevel
+      = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
+
+    Emitted = (DiagLevel != DiagnosticIDs::Ignored);
+    if (Emitted) {
+      // Emit the diagnostic regardless of suppression level.
+      Diags->EmitDiag(*this, DiagLevel);
+    }
+  } else {
+    // Process the diagnostic, sending the accumulated information to the
+    // DiagnosticConsumer.
+    Emitted = ProcessDiag();
+  }
 
   // Clear out the current diagnostic object.
   unsigned DiagID = CurDiagID;
   Clear();
 
   // If there was a delayed diagnostic, emit it now.
-  if (DelayedDiagID && DelayedDiagID != DiagID)
+  if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
     ReportDelayed();
 
   return Emitted;
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 8c33a96..d00573f 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -357,7 +357,7 @@
     return CustomDiagInfo->getLevel(DiagID);
 
   unsigned DiagClass = getBuiltinDiagClass(DiagID);
-  assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
+  if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note;
   return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
 }
 
@@ -583,24 +583,9 @@
   assert(Diag.getClient() && "DiagnosticClient not set!");
 
   // Figure out the diagnostic level of this message.
-  DiagnosticIDs::Level DiagLevel;
   unsigned DiagID = Info.getID();
-
-  if (DiagID >= diag::DIAG_UPPER_LIMIT) {
-    // Handle custom diagnostics, which cannot be mapped.
-    DiagLevel = CustomDiagInfo->getLevel(DiagID);
-  } else {
-    // Get the class of the diagnostic.  If this is a NOTE, map it onto whatever
-    // the diagnostic level was for the previous diagnostic so that it is
-    // filtered the same as the previous diagnostic.
-    unsigned DiagClass = getBuiltinDiagClass(DiagID);
-    if (DiagClass == CLASS_NOTE) {
-      DiagLevel = DiagnosticIDs::Note;
-    } else {
-      DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
-                                     Diag);
-    }
-  }
+  DiagnosticIDs::Level DiagLevel
+    = getDiagnosticLevel(DiagID, Info.getLocation(), Diag);
 
   if (DiagLevel != DiagnosticIDs::Note) {
     // Record that a fatal error occurred only when we see a second
@@ -658,6 +643,14 @@
   }
 
   // Finally, report it.
+  EmitDiag(Diag, DiagLevel);
+  return true;
+}
+
+void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const {
+  Diagnostic Info(&Diag);
+  assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!");
+
   Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
   if (Diag.Client->IncludeInDiagnosticCounts()) {
     if (DiagLevel == DiagnosticIDs::Warning)
@@ -665,8 +658,6 @@
   }
 
   Diag.CurDiagID = ~0U;
-
-  return true;
 }
 
 bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 1d9c196..236b700 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -387,7 +387,7 @@
     OS << ": " << I->second;
   }
 
-  Diags.Report(diag::err_verify_inconsistent_diags)
+  Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
     << Kind << /*Unexpected=*/true << OS.str();
   return std::distance(diag_begin, diag_end);
 }
@@ -411,7 +411,7 @@
     OS << ": " << D.Text;
   }
 
-  Diags.Report(diag::err_verify_inconsistent_diags)
+  Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
     << Kind << /*Unexpected=*/false << OS.str();
   return DL.size();
 }