[TextDiagnosticBuffer] Fix diagnostic note emission order
authorHal Finkel <hfinkel@anl.gov>
Sat, 16 Dec 2017 01:40:19 +0000 (01:40 +0000)
committerHal Finkel <hfinkel@anl.gov>
Sat, 16 Dec 2017 01:40:19 +0000 (01:40 +0000)
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

clang/include/clang/Frontend/TextDiagnosticBuffer.h
clang/lib/Frontend/TextDiagnosticBuffer.cpp
clang/test/Frontend/diagnostics-order.c [new file with mode: 0644]

index 3bcf824455e2dc9764c8dfe28267d890363a6098..23f168e2232df70f0740dc50911ccb44c6a60ad9 100644 (file)
@@ -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<std::pair<DiagnosticsEngine::Level, size_t>> All;
 public:
   const_iterator err_begin() const  { return Errors.begin(); }
   const_iterator err_end() const    { return Errors.end(); }
index d49e983fcd3774b43c93beaa79fc7ba9b43b9226..288507310baab3cdd3157664d9c8b20d84048775 100644 (file)
@@ -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 (file)
index 0000000..e557fc6
--- /dev/null
@@ -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