Skip to content

Commit fc9dd58

Browse files
authored
[flang][driver] add -Wfatal-errors (#147614)
Adds the flag `-Wfatal-errors` which truncates the error messages at 1 error.
1 parent 8f8b1b0 commit fc9dd58

File tree

9 files changed

+100
-15
lines changed

9 files changed

+100
-15
lines changed

flang/include/flang/Frontend/CompilerInvocation.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ class CompilerInvocation : public CompilerInvocationBase {
102102
bool debugModuleDir = false;
103103
bool hermeticModuleFileOutput = false;
104104

105-
bool warnAsErr = false;
106-
107105
// Executable name
108106
const char *argv0;
109107

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

117+
// Fortran Error options
118+
size_t maxErrors = 0;
119+
bool warnAsErr = false;
119120
// Fortran Warning options
120121
bool enableConformanceChecks = false;
121122
bool enableUsageChecks = false;
@@ -189,6 +190,8 @@ class CompilerInvocation : public CompilerInvocationBase {
189190
const bool &getHermeticModuleFileOutput() const {
190191
return hermeticModuleFileOutput;
191192
}
193+
size_t &getMaxErrors() { return maxErrors; }
194+
const size_t &getMaxErrors() const { return maxErrors; }
192195

193196
bool &getWarnAsErr() { return warnAsErr; }
194197
const bool &getWarnAsErr() const { return warnAsErr; }
@@ -261,6 +264,7 @@ class CompilerInvocation : public CompilerInvocationBase {
261264
hermeticModuleFileOutput = flag;
262265
}
263266

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

266270
void setUseAnalyzedObjectsForUnparse(bool flag) {

flang/include/flang/Parser/message.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ class Messages {
354354
void ResolveProvenances(const AllCookedSources &);
355355
void Emit(llvm::raw_ostream &, const AllCookedSources &,
356356
bool echoSourceLines = true,
357-
const common::LanguageFeatureControl *hintFlags = nullptr) const;
357+
const common::LanguageFeatureControl *hintFlags = nullptr,
358+
std::size_t maxErrorsToEmit = 0) const;
358359
void AttachTo(Message &, std::optional<Severity> = std::nullopt);
359360
bool AnyFatalError() const;
360361

flang/include/flang/Semantics/semantics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ class SemanticsContext {
154154
warnOnNonstandardUsage_ = x;
155155
return *this;
156156
}
157+
SemanticsContext &set_maxErrors(size_t x) {
158+
maxErrors_ = x;
159+
return *this;
160+
}
157161
SemanticsContext &set_warningsAreErrors(bool x) {
158162
warningsAreErrors_ = x;
159163
return *this;
@@ -167,6 +171,8 @@ class SemanticsContext {
167171
const DeclTypeSpec &MakeNumericType(TypeCategory, int kind = 0);
168172
const DeclTypeSpec &MakeLogicalType(int kind = 0);
169173

174+
std::size_t maxErrors() const { return maxErrors_; }
175+
170176
bool AnyFatalError() const;
171177

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

222+
void EmitMessages(llvm::raw_ostream &);
223+
216224
const Scope &FindScope(parser::CharBlock) const;
217225
Scope &FindScope(parser::CharBlock);
218226
void UpdateScopeIndex(Scope &, parser::CharBlock);
@@ -322,6 +330,7 @@ class SemanticsContext {
322330
Scope *currentHermeticModuleFileScope_{nullptr};
323331
ScopeIndex scopeIndex_;
324332
parser::Messages messages_;
333+
std::size_t maxErrors_{0};
325334
evaluate::FoldingContext foldingContext_;
326335
ConstructStack constructStack_;
327336
struct IndexVarInfo {

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1029,7 +1029,10 @@ static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
10291029
for (const auto &wArg : wArgs) {
10301030
if (wArg == "error") {
10311031
res.setWarnAsErr(true);
1032-
// -W(no-)<feature>
1032+
// -Wfatal-errors
1033+
} else if (wArg == "fatal-errors") {
1034+
res.setMaxErrors(1);
1035+
// -W[no-]<feature>
10331036
} else if (!features.EnableWarning(wArg)) {
10341037
const unsigned diagID = diags.getCustomDiagID(
10351038
clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");
@@ -1790,6 +1793,7 @@ CompilerInvocation::getSemanticsCtx(
17901793
semanticsContext->set_moduleDirectory(getModuleDir())
17911794
.set_searchDirectories(fortranOptions.searchDirectories)
17921795
.set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories)
1796+
.set_maxErrors(getMaxErrors())
17931797
.set_warningsAreErrors(getWarnAsErr())
17941798
.set_moduleFileSuffix(getModuleFileSuffix())
17951799
.set_underscoring(getCodeGenOpts().Underscoring);

flang/lib/Frontend/FrontendAction.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ bool FrontendAction::runParse(bool emitMessages) {
173173
// combining them with messages from semantics.
174174
const common::LanguageFeatureControl &features{
175175
ci.getInvocation().getFortranOpts().features};
176+
// Default maxErrors here because none are fatal.
176177
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources(),
177178
/*echoSourceLine=*/true, &features);
178179
}
@@ -228,15 +229,16 @@ template <unsigned N>
228229
bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
229230
const common::LanguageFeatureControl &features{
230231
instance->getInvocation().getFortranOpts().features};
232+
const size_t maxErrors{instance->getInvocation().getMaxErrors()};
231233
if (!instance->getParsing().messages().empty() &&
232234
(instance->getInvocation().getWarnAsErr() ||
233235
instance->getParsing().messages().AnyFatalError())) {
234236
const unsigned diagID = instance->getDiagnostics().getCustomDiagID(
235237
clang::DiagnosticsEngine::Error, message);
236238
instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
237-
instance->getParsing().messages().Emit(llvm::errs(),
238-
instance->getAllCookedSources(),
239-
/*echoSourceLines=*/true, &features);
239+
instance->getParsing().messages().Emit(
240+
llvm::errs(), instance->getAllCookedSources(),
241+
/*echoSourceLines=*/true, &features, maxErrors);
240242
return true;
241243
}
242244
if (instance->getParsing().parseTree().has_value() &&
@@ -245,9 +247,9 @@ bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
245247
const unsigned diagID = instance->getDiagnostics().getCustomDiagID(
246248
clang::DiagnosticsEngine::Error, message);
247249
instance->getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
248-
instance->getParsing().messages().Emit(llvm::errs(),
249-
instance->getAllCookedSources(),
250-
/*echoSourceLine=*/true, &features);
250+
instance->getParsing().messages().Emit(
251+
llvm::errs(), instance->getAllCookedSources(),
252+
/*echoSourceLine=*/true, &features, maxErrors);
251253
instance->getParsing().EmitMessage(
252254
llvm::errs(), instance->getParsing().finalRestingPlace(),
253255
"parser FAIL (final position)", "error: ", llvm::raw_ostream::RED);

flang/lib/Parser/message.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,22 +452,31 @@ void Messages::ResolveProvenances(const AllCookedSources &allCooked) {
452452
}
453453

454454
void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
455-
bool echoSourceLines,
456-
const common::LanguageFeatureControl *hintFlagPtr) const {
455+
bool echoSourceLines, const common::LanguageFeatureControl *hintFlagPtr,
456+
std::size_t maxErrorsToEmit) const {
457457
std::vector<const Message *> sorted;
458458
for (const auto &msg : messages_) {
459459
sorted.push_back(&msg);
460460
}
461461
std::stable_sort(sorted.begin(), sorted.end(),
462462
[](const Message *x, const Message *y) { return x->SortBefore(*y); });
463463
const Message *lastMsg{nullptr};
464+
std::size_t errorsEmitted{0};
464465
for (const Message *msg : sorted) {
465466
if (lastMsg && *msg == *lastMsg) {
466467
// Don't emit two identical messages for the same location
467468
continue;
468469
}
469470
msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr);
470471
lastMsg = msg;
472+
if (msg->IsFatal()) {
473+
++errorsEmitted;
474+
}
475+
// If maxErrorsToEmit is 0, emit all errors, otherwise break after
476+
// maxErrorsToEmit.
477+
if (maxErrorsToEmit > 0 && errorsEmitted >= maxErrorsToEmit) {
478+
break;
479+
}
471480
}
472481
}
473482

flang/lib/Semantics/semantics.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,10 +655,10 @@ bool Semantics::Perform() {
655655
void Semantics::EmitMessages(llvm::raw_ostream &os) {
656656
// Resolve the CharBlock locations of the Messages to ProvenanceRanges
657657
// so messages from parsing and semantics are intermixed in source order.
658-
const common::LanguageFeatureControl &features{context_.languageFeatures()};
659658
context_.messages().ResolveProvenances(context_.allCookedSources());
660-
context_.messages().Emit(
661-
os, context_.allCookedSources(), /*echoSourceLine=*/true, &features);
659+
context_.messages().Emit(os, context_.allCookedSources(),
660+
/*echoSourceLine=*/true, &context_.languageFeatures(),
661+
/*maxErrorsToEmit=*/context_.maxErrors());
662662
}
663663

664664
void SemanticsContext::DumpSymbols(llvm::raw_ostream &os) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
!RUN: not %flang_fc1 -fsyntax-only -Wfatal-errors %s 2>&1 | FileCheck %s --check-prefix=CHECK1
2+
!RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s --check-prefix=CHECK2
3+
4+
program p
5+
contains
6+
! CHECK1: fatal-errors-parsing.f90:{{.*}} error:
7+
! CHECK2: fatal-errors-parsing.f90:{{.*}} error:
8+
continue
9+
end
10+
11+
subroutine s
12+
contains
13+
! CHECK1-NOT: error:
14+
! CHECK2: fatal-errors-parsing.f90:{{.*}} error:
15+
continue
16+
end
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
! RUN: not %flang_fc1 %s 2>&1 | FileCheck %s --check-prefix=CHECK1
2+
! RUN: not %flang_fc1 -Wfatal-errors %s 2>&1 | FileCheck %s --check-prefix=CHECK2
3+
4+
module m
5+
contains
6+
subroutine s0(p)
7+
real, pointer, intent(in) :: p
8+
end
9+
subroutine s1(p)
10+
real, pointer, intent(in) :: p(:)
11+
end
12+
subroutine sa(p)
13+
real, pointer, intent(in) :: p(..)
14+
end
15+
subroutine sao(p)
16+
real, intent(in), optional, pointer :: p(..)
17+
end
18+
subroutine soa(a)
19+
real, intent(in), optional, allocatable :: a(..)
20+
end
21+
subroutine test
22+
real, pointer :: a0, a1(:)
23+
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
24+
!CHECK2: fatal-errors-semantics.f90:{{.*}} error:
25+
call s0(null(a1))
26+
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
27+
!CHECK2-NOT: error:
28+
call s1(null(a0))
29+
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
30+
!CHECK2-NOT: error:
31+
call sa(null())
32+
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
33+
!CHECK2-NOT: error:
34+
call sao(null())
35+
!CHECK1: fatal-errors-semantics.f90:{{.*}} error:
36+
!CHECK2-NOT: error:
37+
call soa(null())
38+
end
39+
end
40+

0 commit comments

Comments
 (0)