]> granicus.if.org Git - clang/commitdiff
Emit -verify diagnostics even when we have a fatal error.
authorJordan Rose <jordan_rose@apple.com>
Wed, 11 Jul 2012 16:50:36 +0000 (16:50 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 11 Jul 2012 16:50:36 +0000 (16:50 +0000)
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

include/clang/Basic/Diagnostic.h
include/clang/Basic/DiagnosticIDs.h
lib/Basic/Diagnostic.cpp
lib/Basic/DiagnosticIDs.cpp
lib/Frontend/VerifyDiagnosticConsumer.cpp

index 7e2227b52f67210d3027c2dc8e58e13ebc0d8ceb..8b4d3a0b608fca133b22af38f6284d4fd7005ae1 100644 (file)
@@ -763,7 +763,9 @@ protected:
   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 @@ class DiagnosticBuilder {
   // 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 @@ protected:
   void Clear() const {
     DiagObj = 0;
     IsActive = false;
+    IsForceEmit = false;
   }
 
   /// \brief Determine whether this diagnostic is still active.
@@ -879,7 +888,7 @@ protected:
     FlushCounts();
 
     // Process the diagnostic.
-    bool Result = DiagObj->EmitCurrentDiagnostic();
+    bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
 
     // This diagnostic is dead.
     Clear();
@@ -893,6 +902,7 @@ public:
   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 @@ public:
     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
index 3642da11976aece8a075dd44657737e76441c1d3..148a14eed037056864b47ac556743f96bdcc4e14 100644 (file)
@@ -268,6 +268,10 @@ private:
   /// 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;
index fdc37b63cba03360440e7eac1eadbd8d3a036173..6e79b85a99421a700d0b0a242462d48b02c489bd 100644 (file)
@@ -382,17 +382,34 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
   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;
index 8c33a963c927572a3aafc1b52795a175873a2d42..d00573fec523fe220a49340eb35210cab7e2fd43 100644 (file)
@@ -357,7 +357,7 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
     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 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
   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 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
   }
 
   // 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 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
   }
 
   Diag.CurDiagID = ~0U;
-
-  return true;
 }
 
 bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
index 1d9c19644392b4dc3a76403093363d7d042670b8..236b70066296dbc748ffef3e02fbbefd9fd4885d 100644 (file)
@@ -387,7 +387,7 @@ static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceM
     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 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr
     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();
 }