Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions flang/include/flang/Frontend/CompilerInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ class CompilerInvocation : public CompilerInvocationBase {
bool debugModuleDir = false;
bool hermeticModuleFileOutput = false;

bool warnAsErr = false;

// Executable name
const char *argv0;

Expand All @@ -116,6 +114,9 @@ class CompilerInvocation : public CompilerInvocationBase {
// Fortran Dialect options
Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;

// Fortran Error options
size_t maxErrors = 0;
bool warnAsErr = false;
// Fortran Warning options
bool enableConformanceChecks = false;
bool enableUsageChecks = false;
Expand Down Expand Up @@ -189,6 +190,8 @@ class CompilerInvocation : public CompilerInvocationBase {
const bool &getHermeticModuleFileOutput() const {
return hermeticModuleFileOutput;
}
size_t &getMaxErrors() { return maxErrors; }
const size_t &getMaxErrors() const { return maxErrors; }

bool &getWarnAsErr() { return warnAsErr; }
const bool &getWarnAsErr() const { return warnAsErr; }
Expand Down Expand Up @@ -261,6 +264,7 @@ class CompilerInvocation : public CompilerInvocationBase {
hermeticModuleFileOutput = flag;
}

void setMaxErrors(size_t maxErrors) { this->maxErrors = maxErrors; }
void setWarnAsErr(bool flag) { warnAsErr = flag; }

void setUseAnalyzedObjectsForUnparse(bool flag) {
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Parser/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ class Messages {
void ResolveProvenances(const AllCookedSources &);
void Emit(llvm::raw_ostream &, const AllCookedSources &,
bool echoSourceLines = true,
const common::LanguageFeatureControl *hintFlags = nullptr) const;
const common::LanguageFeatureControl *hintFlags = nullptr,
std::size_t maxErrorsToEmit = 0) const;
void AttachTo(Message &, std::optional<Severity> = std::nullopt);
bool AnyFatalError() const;

Expand Down
9 changes: 9 additions & 0 deletions flang/include/flang/Semantics/semantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ class SemanticsContext {
warnOnNonstandardUsage_ = x;
return *this;
}
SemanticsContext &set_maxErrors(size_t x) {
maxErrors_ = x;
return *this;
}
SemanticsContext &set_warningsAreErrors(bool x) {
warningsAreErrors_ = x;
return *this;
Expand All @@ -167,6 +171,8 @@ class SemanticsContext {
const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0);
const DeclTypeSpec &MakeLogicalType(int kind = 0);

std::size_t maxErrors() const { return maxErrors_; }

bool AnyFatalError() const;

// Test or set the Error flag on a Symbol
Expand Down Expand Up @@ -213,6 +219,8 @@ class SemanticsContext {
return Warn(warning, *location_, std::forward<A>(args)...);
}

void EmitMessages(llvm::raw_ostream &);

const Scope &FindScope(parser::CharBlock) const;
Scope &FindScope(parser::CharBlock);
void UpdateScopeIndex(Scope &, parser::CharBlock);
Expand Down Expand Up @@ -322,6 +330,7 @@ class SemanticsContext {
Scope *currentHermeticModuleFileScope_{nullptr};
ScopeIndex scopeIndex_;
parser::Messages messages_;
std::size_t maxErrors_{0};
evaluate::FoldingContext foldingContext_;
ConstructStack constructStack_;
struct IndexVarInfo {
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,10 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
for (const auto &wArg : wArgs) {
if (wArg == "error") {
res.setWarnAsErr(true);
// -W(no-)<feature>
// -Wfatal-errors
} else if (wArg == "fatal-errors") {
res.setMaxErrors(1);
// -W[no-]<feature>
} else if (!features.EnableWarning(wArg)) {
const unsigned diagID = diags.getCustomDiagID(
clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
Expand Down Expand Up @@ -1775,6 +1778,7 @@ CompilerInvocation::getSemanticsCtx(
semanticsContext->set_moduleDirectory(getModuleDir())
.set_searchDirectories(fortranOptions.searchDirectories)
.set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories)
.set_maxErrors(getMaxErrors())
.set_warningsAreErrors(getWarnAsErr())
.set_moduleFileSuffix(getModuleFileSuffix())
.set_underscoring(getCodeGenOpts().Underscoring);
Expand Down
14 changes: 8 additions & 6 deletions flang/lib/Frontend/FrontendAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ bool FrontendAction::runParse(bool emitMessages) {
// combining them with messages from semantics.
const common::LanguageFeatureControl &features{
ci.getInvocation().getFortranOpts().features};
// Default maxErrors here because none are fatal.
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources(),
/*echoSourceLine=*/true, &features);
}
Expand Down Expand Up @@ -228,15 +229,16 @@ template <unsigned N>
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 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);
instance->getParsing().messages().Emit(
llvm::errs(), instance->getAllCookedSources(),
/*echoSourceLines=*/true, &features, maxErrors);
return true;
}
if (instance->getParsing().parseTree().has_value() &&
Expand All @@ -245,9 +247,9 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
const unsigned diagID = instance->getDiagnostics().getCustomDiagID(
clang::DiagnosticsEngine::Error, message);
instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
instance->getParsing().messages().Emit(llvm::errs(),
instance->getAllCookedSources(),
/*echoSourceLine=*/true, &features);
instance->getParsing().messages().Emit(
llvm::errs(), instance->getAllCookedSources(),
/*echoSourceLine=*/true, &features, maxErrors);
instance->getParsing().EmitMessage(
llvm::errs(), instance->getParsing().finalRestingPlace(),
"parser FAIL (final position)", "error: ", llvm::raw_ostream::RED);
Expand Down
13 changes: 11 additions & 2 deletions flang/lib/Parser/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,22 +452,31 @@ void Messages::ResolveProvenances(const AllCookedSources &allCooked) {
}

void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
bool echoSourceLines,
const common::LanguageFeatureControl *hintFlagPtr) const {
bool echoSourceLines, const common::LanguageFeatureControl *hintFlagPtr,
std::size_t maxErrorsToEmit) const {
std::vector<const Message *> sorted;
for (const auto &msg : messages_) {
sorted.push_back(&msg);
}
std::stable_sort(sorted.begin(), sorted.end(),
[](const Message *x, const Message *y) { return x->SortBefore(*y); });
const Message *lastMsg{nullptr};
std::size_t errorsEmitted{0};
for (const Message *msg : sorted) {
if (lastMsg && *msg == *lastMsg) {
// Don't emit two identical messages for the same location
continue;
}
msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr);
lastMsg = msg;
if (msg->IsFatal()) {
++errorsEmitted;
}
// If maxErrorsToEmit is 0, emit all errors, otherwise break after
// maxErrorsToEmit.
if (maxErrorsToEmit > 0 && errorsEmitted >= maxErrorsToEmit) {
break;
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions flang/lib/Semantics/semantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,10 +655,10 @@ bool Semantics::Perform() {
void Semantics::EmitMessages(llvm::raw_ostream &os) {
// Resolve the CharBlock locations of the Messages to ProvenanceRanges
// so messages from parsing and semantics are intermixed in source order.
const common::LanguageFeatureControl &features{context_.languageFeatures()};
context_.messages().ResolveProvenances(context_.allCookedSources());
context_.messages().Emit(
os, context_.allCookedSources(), /*echoSourceLine=*/true, &features);
context_.messages().Emit(os, context_.allCookedSources(),
/*echoSourceLine=*/true, &context_.languageFeatures(),
/*maxErrorsToEmit=*/context_.maxErrors());
}

void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
Expand Down
16 changes: 16 additions & 0 deletions flang/test/Driver/fatal-errors-parsing.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
!RUN: not %flang_fc1 -fsyntax-only -Wfatal-errors %s 2>&1 | FileCheck %s --check-prefix=CHECK1
!RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK2

program p
contains
! CHECK1: fatal-errors-parsing.f90:{{.*}} error:
! CHECK2: fatal-errors-parsing.f90:{{.*}} error:
continue
end

subroutine s
contains
! CHECK1-NOT: error:
! CHECK2: fatal-errors-parsing.f90:{{.*}} error:
continue
end
40 changes: 40 additions & 0 deletions flang/test/Driver/fatal-errors-semantics.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
! RUN: not %flang_fc1 %s 2>&1 | FileCheck %s --check-prefix=CHECK1
! RUN: not %flang_fc1 -Wfatal-errors %s 2>&1 | FileCheck %s --check-prefix=CHECK2

module m
contains
subroutine s0(p)
real, pointer, intent(in) :: p
end
subroutine s1(p)
real, pointer, intent(in) :: p(:)
end
subroutine sa(p)
real, pointer, intent(in) :: p(..)
end
subroutine sao(p)
real, intent(in), optional, pointer :: p(..)
end
subroutine soa(a)
real, intent(in), optional, allocatable :: a(..)
end
subroutine test
real, pointer :: a0, a1(:)
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
!CHECK2: fatal-errors-semantics.f90:{{.*}} error:
call s0(null(a1))
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
!CHECK2-NOT: error:
call s1(null(a0))
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
!CHECK2-NOT: error:
call sa(null())
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
!CHECK2-NOT: error:
call sao(null())
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
!CHECK2-NOT: error:
call soa(null())
end
end