diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -544,6 +544,7 @@ DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete; ~DiagnosticsEngine(); + friend void DiagnosticTestHelper(); LLVM_DUMP_METHOD void dump() const; LLVM_DUMP_METHOD void dump(StringRef DiagName) const; @@ -887,9 +888,9 @@ LastDiagLevel = Other.LastDiagLevel; } - /// Reset the state of the diagnostic object to its initial - /// configuration. - void Reset(); + /// Reset the state of the diagnostic object to its initial configuration. + /// \param[in] soft - if true, doesn't reset the diagnostic mappings and state + void Reset(bool soft = false); //===--------------------------------------------------------------------===// // DiagnosticsEngine classification and reporting interfaces. diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -130,7 +130,7 @@ return true; } -void DiagnosticsEngine::Reset() { +void DiagnosticsEngine::Reset(bool soft /*=false*/) { ErrorOccurred = false; UncompilableErrorOccurred = false; FatalErrorOccurred = false; @@ -145,15 +145,17 @@ LastDiagLevel = DiagnosticIDs::Ignored; DelayedDiagID = 0; - // Clear state related to #pragma diagnostic. - DiagStates.clear(); - DiagStatesByLoc.clear(); - DiagStateOnPushStack.clear(); + if (!soft) { + // Clear state related to #pragma diagnostic. + DiagStates.clear(); + DiagStatesByLoc.clear(); + DiagStateOnPushStack.clear(); - // Create a DiagState and DiagStatePoint representing diagnostic changes - // through command-line. - DiagStates.emplace_back(); - DiagStatesByLoc.appendFirst(&DiagStates.back()); + // Create a DiagState and DiagStatePoint representing diagnostic changes + // through command-line. + DiagStates.emplace_back(); + DiagStatesByLoc.appendFirst(&DiagStates.back()); + } } void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, diff --git a/test/Interpreter/error-recovery-pragmas.cpp b/test/Interpreter/error-recovery-pragmas.cpp new file mode 100644 --- /dev/null +++ b/test/Interpreter/error-recovery-pragmas.cpp @@ -0,0 +1,6 @@ +// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmultichar" +// Reset should not delete #pragmas +error; // expected-error {{use of undeclared identifier}} +void no_diag_multichar(void) { char c = (char)'ab'; } diff --git a/tools/clang-repl/ClangRepl.cpp b/tools/clang-repl/ClangRepl.cpp --- a/tools/clang-repl/ClangRepl.cpp +++ b/tools/clang-repl/ClangRepl.cpp @@ -86,14 +86,17 @@ llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); } + bool hadErrors = false; if (OptInputs.empty()) { llvm::LineEditor LE("clang-repl"); // FIXME: Add LE.setListCompleter while (llvm::Optional Line = LE.readLine()) { if (*Line == "quit") break; - if (auto Err = Interp->ParseAndExecute(*Line)) + if (auto Err = Interp->ParseAndExecute(*Line)) { llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: "); + hadErrors = true; + } } } @@ -104,5 +107,5 @@ llvm::llvm_shutdown(); - return 0; + return hadErrors; } diff --git a/unittests/Basic/DiagnosticTest.cpp b/unittests/Basic/DiagnosticTest.cpp --- a/unittests/Basic/DiagnosticTest.cpp +++ b/unittests/Basic/DiagnosticTest.cpp @@ -14,8 +14,18 @@ using namespace llvm; using namespace clang; + namespace { +void DiagnosticsEngine::DiagnosticTestHelper() { + unsigned delayedDiagID = 0U; + + EXPECT_EQ(this.DelayedDiagID, delayedDiagID); + EXPECT_FALSE(this.DiagStates.empty()); + EXPECT_FALSE(this.DiagStatesByLoc.empty()); + EXPECT_FALSE(this.DiagStateOnPushStack.empty()); +} + // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics. TEST(DiagnosticTest, suppressAndTrap) { DiagnosticsEngine Diags(new DiagnosticIDs(), @@ -71,6 +81,32 @@ EXPECT_EQ(Diags.getNumWarnings(), FatalsAsError); } } + +// Check that soft RESET works as intended +TEST(DiagnosticTest, softReset) { + DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, + new IgnoringDiagConsumer()); + + unsigned numWarnings = 0U, numErrors = 0U; + + Diags.Reset(true); + // Check For ErrorOccurred and TrapNumErrorsOccurred + EXPECT_FALSE(Diags.hasErrorOccurred()); + EXPECT_FALSE(Diags.hasFatalErrorOccurred()); + EXPECT_FALSE(Diags.hasUncompilableErrorOccurred()); + // Check for UnrecoverableErrorOccurred and TrapNumUnrecoverableErrorsOccurred + EXPECT_FALSE(Diags.hasUnrecoverableErrorOccurred()); + + EXPECT_EQ(Diags.getNumWarnings(), numWarnings); + EXPECT_EQ(Diags.getNumErrors(), numErrors); + + // Check for private variables of DiagnosticsEngine differentiating soft reset + Diags.DiagnosticTestHelper(); + + EXPECT_FALSE(Diags.isDiagnosticInFlight()); + EXPECT_TRUE(Diags.isLastDiagnosticIgnored()); +} + TEST(DiagnosticTest, diagnosticError) { DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, new IgnoringDiagConsumer());