]> granicus.if.org Git - clang/commitdiff
DiagnosticsEngine should clear DelayedDiagID before reporting the
authorAlex Lorenz <arphaman@gmail.com>
Thu, 4 May 2017 13:56:51 +0000 (13:56 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 4 May 2017 13:56:51 +0000 (13:56 +0000)
delayed diagnostic

This fix avoids an infinite recursion that was uncovered in one of our internal
tests by r301992. The testcase is the most reduced version of that
auto-generated test.

This is an improved version of the reverted commit r302037. The previous fix
actually managed to expose another subtle bug whereby `fatal_too_many_errors`
error was reported twice, with the second report setting the
`FatalErrorOccurred` flag. That prevented the notes that followed the diagnostic
the caused `fatal_too_many_errors` to be emitted. This commit ensures that notes
that follow `fatal_too_many_errors` but that belong to the diagnostic that
caused `fatal_too_many_errors` won't be emitted by setting the
`FatalErrorOccurred` when emitting `fatal_too_many_errors`.

rdar://31962618

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@302151 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Basic/Diagnostic.cpp
lib/Basic/DiagnosticIDs.cpp
test/Index/KeepGoingWithLotsOfErrors.mm [new file with mode: 0644]

index 6bdef78c074f7fb4337590a156121689bfeb1af0..c355445dc1e715d052bd8725ba94ba628e61fe34 100644 (file)
@@ -146,10 +146,9 @@ void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
 }
 
 void DiagnosticsEngine::ReportDelayed() {
-  Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
+  unsigned ID = DelayedDiagID;
   DelayedDiagID = 0;
-  DelayedDiagArg1.clear();
-  DelayedDiagArg2.clear();
+  Report(ID) << DelayedDiagArg1 << DelayedDiagArg2;
 }
 
 void DiagnosticsEngine::DiagStateMap::appendFirst(
@@ -420,11 +419,10 @@ bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
   }
 
   // Clear out the current diagnostic object.
-  unsigned DiagID = CurDiagID;
   Clear();
 
   // If there was a delayed diagnostic, emit it now.
-  if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
+  if (!Force && DelayedDiagID)
     ReportDelayed();
 
   return Emitted;
index 2852b40026c2bed66f4b140c58c3d6e28282a7db..ce493c1e5caba8e5aadeab3d8cf76454d796d7eb 100644 (file)
@@ -666,6 +666,10 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
     }
   }
 
+  // Make sure we set FatalErrorOccurred to ensure that the notes from the
+  // diagnostic that caused `fatal_too_many_errors` won't be emitted.
+  if (Diag.CurDiagID == diag::fatal_too_many_errors)
+    Diag.FatalErrorOccurred = true;
   // Finally, report it.
   EmitDiag(Diag, DiagLevel);
   return true;
diff --git a/test/Index/KeepGoingWithLotsOfErrors.mm b/test/Index/KeepGoingWithLotsOfErrors.mm
new file mode 100644 (file)
index 0000000..078ea6e
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: env CINDEXTEST_KEEP_GOING=1 c-index-test -code-completion-at=%s:25:1 %s
+// Shouldn't crash!
+// This is the minimized test that triggered an infinite recursion:
+
++(BOOL) onEntity {
+}
+
+-(const Object &) a_200 {
+}
+
+-(int) struct {
+}
+
+-(int) bar {
+}
+
+-(int) part {
+}
+
++(some_type_t) piece {
+}
+
++(void) z_Z_42 {
+  ([self onEntity: [] { 42];
+  } class: ^ {  }
+];
+  [super];
+  BOOL struct;
+}