diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h index db1a0a65157e3..9192d23529913 100644 --- a/flang/include/flang/Parser/message.h +++ b/flang/include/flang/Parser/message.h @@ -355,9 +355,9 @@ class Messages { void Emit(llvm::raw_ostream &, const AllCookedSources &, bool echoSourceLines = true, const common::LanguageFeatureControl *hintFlags = nullptr, - std::size_t maxErrorsToEmit = 0) const; + std::size_t maxErrorsToEmit = 0, bool warningsAreErrors = false) const; void AttachTo(Message &, std::optional = std::nullopt); - bool AnyFatalError() const; + bool AnyFatalError(bool warningsAreErrors = false) const; private: std::list messages_; diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp index 2429e07e5b8c4..58901c6000380 100644 --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -230,15 +230,14 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) { const common::LanguageFeatureControl &features{ instance->getInvocation().getFortranOpts().features}; const size_t maxErrors{instance->getInvocation().getMaxErrors()}; - if (!instance->getParsing().messages().empty() && - (instance->getInvocation().getWarnAsErr() || - instance->getParsing().messages().AnyFatalError())) { + const bool warningsAreErrors{instance->getInvocation().getWarnAsErr()}; + if (instance->getParsing().messages().AnyFatalError(warningsAreErrors)) { const unsigned diagID = instance->getDiagnostics().getCustomDiagID( clang::DiagnosticsEngine::Error, message); instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); instance->getParsing().messages().Emit( llvm::errs(), instance->getAllCookedSources(), - /*echoSourceLines=*/true, &features, maxErrors); + /*echoSourceLines=*/true, &features, maxErrors, warningsAreErrors); return true; } if (instance->getParsing().parseTree().has_value() && @@ -249,7 +248,7 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) { instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName(); instance->getParsing().messages().Emit( llvm::errs(), instance->getAllCookedSources(), - /*echoSourceLine=*/true, &features, maxErrors); + /*echoSourceLine=*/true, &features, maxErrors, warningsAreErrors); instance->getParsing().EmitMessage( llvm::errs(), instance->getParsing().finalRestingPlace(), "parser FAIL (final position)", "error: ", llvm::raw_ostream::RED); diff --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp index 909fba948a45a..2a8101dd0b810 100644 --- a/flang/lib/Parser/message.cpp +++ b/flang/lib/Parser/message.cpp @@ -453,7 +453,7 @@ void Messages::ResolveProvenances(const AllCookedSources &allCooked) { void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked, bool echoSourceLines, const common::LanguageFeatureControl *hintFlagPtr, - std::size_t maxErrorsToEmit) const { + std::size_t maxErrorsToEmit, bool warningsAreErrors) const { std::vector sorted; for (const auto &msg : messages_) { sorted.push_back(&msg); @@ -469,7 +469,7 @@ void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked, } msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr); lastMsg = msg; - if (msg->IsFatal()) { + if (warningsAreErrors || msg->IsFatal()) { ++errorsEmitted; } // If maxErrorsToEmit is 0, emit all errors, otherwise break after @@ -491,7 +491,18 @@ void Messages::AttachTo(Message &msg, std::optional severity) { messages_.clear(); } -bool Messages::AnyFatalError() const { +bool Messages::AnyFatalError(bool warningsAreErrors) const { + // Short-circuit in the most common case. + if (messages_.empty()) { + return false; + } + // If warnings are errors and there are warnings or errors, this is fatal. + // This preserves the compiler's current behavior of treating any non-fatal + // message as a warning. We may want to refine this in the future. + if (warningsAreErrors) { + return true; + } + // Otherwise, check the message buffer for fatal errors. for (const auto &msg : messages_) { if (msg.IsFatal()) { return true; diff --git a/flang/lib/Semantics/semantics.cpp b/flang/lib/Semantics/semantics.cpp index ab78605d01f4c..b15ed057b52f2 100644 --- a/flang/lib/Semantics/semantics.cpp +++ b/flang/lib/Semantics/semantics.cpp @@ -376,8 +376,7 @@ const DeclTypeSpec &SemanticsContext::MakeLogicalType(int kind) { } bool SemanticsContext::AnyFatalError() const { - return !messages_.empty() && - (warningsAreErrors_ || messages_.AnyFatalError()); + return messages_.AnyFatalError(warningsAreErrors_); } bool SemanticsContext::HasError(const Symbol &symbol) { return errorSymbols_.count(symbol) > 0; @@ -658,7 +657,7 @@ void Semantics::EmitMessages(llvm::raw_ostream &os) { context_.messages().ResolveProvenances(context_.allCookedSources()); context_.messages().Emit(os, context_.allCookedSources(), /*echoSourceLine=*/true, &context_.languageFeatures(), - /*maxErrorsToEmit=*/context_.maxErrors()); + context_.maxErrors(), context_.warningsAreErrors()); } void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) { diff --git a/flang/test/Driver/fatal-errors-warnings.f90 b/flang/test/Driver/fatal-errors-warnings.f90 new file mode 100644 index 0000000000000..2de09c3ed0778 --- /dev/null +++ b/flang/test/Driver/fatal-errors-warnings.f90 @@ -0,0 +1,31 @@ +! RUN: %flang_fc1 -Wfatal-errors -pedantic %s 2>&1 | FileCheck %s --check-prefix=CHECK1 +! RUN: not %flang_fc1 -pedantic -Werror %s 2>&1 | FileCheck %s --check-prefix=CHECK2 +! RUN: not %flang_fc1 -Wfatal-errors -pedantic -Werror %s 2>&1 | FileCheck %s --check-prefix=CHECK3 + +module m + contains + subroutine foo(a) + real, intent(in), target :: a(:) + end subroutine +end module + +program test + use m + real, target :: a(1) + real :: b(1) + call foo(a) ! ok + !CHECK1: fatal-errors-warnings.f90:{{.*}} warning: + !CHECK2: fatal-errors-warnings.f90:{{.*}} warning: + !CHECK3: fatal-errors-warnings.f90:{{.*}} warning: + call foo(b) + !CHECK1: fatal-errors-warnings.f90:{{.*}} warning: + !CHECK2: fatal-errors-warnings.f90:{{.*}} warning: + !CHECK3-NOT: error: + !CHECK3-NOT: warning: + call foo((a)) + !CHECK1: fatal-errors-warnings.f90:{{.*}} warning: + !CHECK2: fatal-errors-warnings.f90:{{.*}} warning: + call foo(a([1])) + !! Hard error instead of warning if uncommented. + !call foo(a(1)) +end \ No newline at end of file