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
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; }
// 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!");
}
void Clear() const {
DiagObj = 0;
IsActive = false;
+ IsForceEmit = false;
}
/// \brief Determine whether this diagnostic is still active.
FlushCounts();
// Process the diagnostic.
- bool Result = DiagObj->EmitCurrentDiagnostic();
+ bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
// This diagnostic is dead.
Clear();
DiagnosticBuilder(const DiagnosticBuilder &D) {
DiagObj = D.DiagObj;
IsActive = D.IsActive;
+ IsForceEmit = D.IsForceEmit;
D.Clear();
NumArgs = D.NumArgs;
NumRanges = D.NumRanges;
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
/// 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;
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;
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);
}
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
}
// 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)
}
Diag.CurDiagID = ~0U;
-
- return true;
}
bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
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);
}
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();
}