Index: include/clang/Frontend/TextDiagnosticBuffer.h =================================================================== --- include/clang/Frontend/TextDiagnosticBuffer.h +++ include/clang/Frontend/TextDiagnosticBuffer.h @@ -29,6 +29,11 @@ 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(); } Index: lib/Frontend/TextDiagnosticBuffer.cpp =================================================================== --- lib/Frontend/TextDiagnosticBuffer.cpp +++ lib/Frontend/TextDiagnosticBuffer.cpp @@ -30,34 +30,45 @@ 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; + } + } } Index: test/Frontend/diagnostics-order.c =================================================================== --- /dev/null +++ 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