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 @@ -545,6 +545,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; @@ -891,9 +892,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/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -203,8 +203,8 @@ } } - // FIXME: Do not reset the pragma handlers. - Diags.Reset(); + Diags.Reset(/*soft=*/true); + Diags.getClient()->clear(); return llvm::make_error("Parsing failed.", std::error_code()); } 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 @@ -48,6 +48,23 @@ exit(GenCrashDiag ? 70 : 1); } +// If we are running with -verify a reported has to be returned as unsuccess. +// This is relevant especially for the test suite. +static int checkDiagErrors(const clang::CompilerInstance *CI) { + unsigned Errs = CI->getDiagnostics().getClient()->getNumErrors(); + if (CI->getDiagnosticOpts().VerifyDiagnostics) { + // If there was an error that came from the verifier we must return 1 as + // an exit code for the process. This will make the test fail as expected. + clang::DiagnosticConsumer *Client = CI->getDiagnostics().getClient(); + Client->EndSourceFile(); + Errs = Client->getNumErrors(); + + // The interpreter expects BeginSourceFile/EndSourceFiles to be balanced. + Client->BeginSourceFile(CI->getLangOpts(), &CI->getPreprocessor()); + } + return Errs ? EXIT_FAILURE : EXIT_SUCCESS; +} + llvm::ExitOnError ExitOnErr; int main(int argc, const char **argv) { ExitOnErr.setBanner("clang-repl: "); @@ -106,5 +123,5 @@ llvm::llvm_shutdown(); - return 0; + return checkDiagErrors(Interp->getCompilerInstance()); } 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());