From cc15219fb1eb7d536fb40ffed7e4a6a779eb23ff Mon Sep 17 00:00:00 2001 From: Hal Finkel Date: Sat, 16 Dec 2017 01:40:19 +0000 Subject: [PATCH] [TextDiagnosticBuffer] Fix diagnostic note emission order The frontend currently groups diagnostics from the command line according to diagnostic level, but that places all notes last. Fix that by emitting such diagnostics in the order they were generated. Patch by Joel E. Denny, thanks! Differential Revision: https://reviews.llvm.org/D40995 llvm-svn: 320904 --- .../include/clang/Frontend/TextDiagnosticBuffer.h | 5 +++ clang/lib/Frontend/TextDiagnosticBuffer.cpp | 37 ++++++++++++++-------- clang/test/Frontend/diagnostics-order.c | 10 ++++++ 3 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 clang/test/Frontend/diagnostics-order.c diff --git a/clang/include/clang/Frontend/TextDiagnosticBuffer.h b/clang/include/clang/Frontend/TextDiagnosticBuffer.h index 3bcf824..23f168e 100644 --- a/clang/include/clang/Frontend/TextDiagnosticBuffer.h +++ b/clang/include/clang/Frontend/TextDiagnosticBuffer.h @@ -29,6 +29,11 @@ public: typedef DiagList::const_iterator const_iterator; private: DiagList Errors, Warnings, Remarks, Notes; + /// All - All diagnostics in the order in which they were generated. That + /// order likely doesn't correspond to user input order, but it at least + /// keeps notes in the right places. Each pair in the vector is a diagnostic + /// level and an index into the corresponding DiagList above. + std::vector> All; public: const_iterator err_begin() const { return Errors.begin(); } const_iterator err_end() const { return Errors.end(); } diff --git a/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/clang/lib/Frontend/TextDiagnosticBuffer.cpp index d49e983..2885073 100644 --- a/clang/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -30,34 +30,45 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level, default: llvm_unreachable( "Diagnostic not handled during diagnostic buffering!"); case DiagnosticsEngine::Note: + All.emplace_back(Level, Notes.size()); Notes.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Warning: + All.emplace_back(Level, Warnings.size()); Warnings.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Remark: + All.emplace_back(Level, Remarks.size()); Remarks.emplace_back(Info.getLocation(), Buf.str()); break; case DiagnosticsEngine::Error: case DiagnosticsEngine::Fatal: + All.emplace_back(Level, Errors.size()); Errors.emplace_back(Info.getLocation(), Buf.str()); break; } } void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { - // FIXME: Flush the diagnostics in order. - for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) - << it->second; - for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning, "%0")) - << it->second; - for (const_iterator it = remark_begin(), ie = remark_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Remark, "%0")) - << it->second; - for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) - Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0")) - << it->second; + for (auto it = All.begin(), ie = All.end(); it != ie; ++it) { + auto Diag = Diags.Report(Diags.getCustomDiagID(it->first, "%0")); + switch (it->first) { + default: llvm_unreachable( + "Diagnostic not handled during diagnostic flushing!"); + case DiagnosticsEngine::Note: + Diag << Notes[it->second].second; + break; + case DiagnosticsEngine::Warning: + Diag << Warnings[it->second].second; + break; + case DiagnosticsEngine::Remark: + Diag << Remarks[it->second].second; + break; + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: + Diag << Errors[it->second].second; + break; + } + } } diff --git a/clang/test/Frontend/diagnostics-order.c b/clang/test/Frontend/diagnostics-order.c new file mode 100644 index 0000000..e557fc6 --- /dev/null +++ b/clang/test/Frontend/diagnostics-order.c @@ -0,0 +1,10 @@ +// Make sure a note stays with its associated command-line argument diagnostic. +// Previously, these diagnostics were grouped by diagnostic level with all +// notes last. +// +// RUN: not %clang_cc1 -O999 -std=bogus %s 2> %t +// RUN: FileCheck < %t %s +// +// CHECK: warning: optimization level '-O999' is not supported +// CHECK-NEXT: error: invalid value 'bogus' in '-std=bogus' +// CHECK-NEXT: note: use {{.*}} for {{.*}} standard -- 2.7.4