From c6d64a26c28bbeee50e06c94c4f4c08e610327b7 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 11 Jul 2012 16:50:36 +0000 Subject: [PATCH] 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 --- include/clang/Basic/Diagnostic.h | 24 +++++++++++++++--- include/clang/Basic/DiagnosticIDs.h | 4 +++ lib/Basic/Diagnostic.cpp | 27 ++++++++++++++++---- lib/Basic/DiagnosticIDs.cpp | 31 ++++++++--------------- lib/Frontend/VerifyDiagnosticConsumer.cpp | 4 +-- 5 files changed, 59 insertions(+), 31 deletions(-) diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 7e2227b52f..8b4d3a0b60 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -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 diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index 3642da1197..148a14eed0 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -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; diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index fdc37b63cb..6e79b85a99 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -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; diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 8c33a963c9..d00573fec5 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -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 { diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 1d9c196443..236b700662 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -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(); } -- 2.40.0