diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -544,6 +544,7 @@ DiagnosticsEngine &operator=(const DiagnosticsEngine &) = delete; ~DiagnosticsEngine(); + friend void DiagnosticsTestHelper(DiagnosticsEngine &); 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/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/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/clang/test/Interpreter/error-recovery-pragmas.cpp b/clang/test/Interpreter/error-recovery-pragmas.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Interpreter/error-recovery-pragmas.cpp @@ -0,0 +1,7 @@ +// 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'; } +quit diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/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/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp --- a/clang/unittests/Basic/DiagnosticTest.cpp +++ b/clang/unittests/Basic/DiagnosticTest.cpp @@ -14,6 +14,15 @@ using namespace llvm; using namespace clang; +void clang::DiagnosticsTestHelper(DiagnosticsEngine &diag) { + unsigned delayedDiagID = 0U; + + EXPECT_EQ(diag.DelayedDiagID, delayedDiagID); + EXPECT_FALSE(diag.DiagStates.empty()); + EXPECT_TRUE(diag.DiagStatesByLoc.empty()); + EXPECT_TRUE(diag.DiagStateOnPushStack.empty()); +} + namespace { // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics. @@ -71,6 +80,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 + DiagnosticsTestHelper(Diags); + + EXPECT_FALSE(Diags.isDiagnosticInFlight()); + EXPECT_TRUE(Diags.isLastDiagnosticIgnored()); +} + TEST(DiagnosticTest, diagnosticError) { DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, new IgnoringDiagConsumer());