Skip to content

Commit f2e8089

Browse files
authored
[flang] Intermix messages from parser and semantic analysis (#90654)
When there are one or more fatal error messages produced by the parser, semantic analysis is not performed. But when there are messages produced by the parser and none of them are fatal, those messages are emitted to the user before compilation continues with semantic analysis, and any messages produced by semantics are emitted after the messages from parsing. This can be confusing for the user, as the messages may no longer all be in source file location order. It also makes it difficult to write tests that check for both non-fatal messages from parsing as well as messages from semantics using inline CHECK: or other expected messages in test source code. This patch ensures that if semantic analysis is performed, and non-fatal messages were produced by the parser, that all the messages will be combined and emitted in source file order.
1 parent b8c301f commit f2e8089

File tree

8 files changed

+43
-22
lines changed

8 files changed

+43
-22
lines changed

flang/examples/FeatureList/FeatureList.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,9 @@ class FeatureListAction : public PluginParseTreeAction {
775775
}
776776
}
777777

778-
bool beginSourceFileAction() override { return runPrescan() && runParse(); }
778+
bool beginSourceFileAction() override {
779+
return runPrescan() && runParse(/*emitMessages=*/true);
780+
}
779781
};
780782

781783
static FrontendPluginRegistry::Add<FeatureListAction> X(

flang/include/flang/Frontend/FrontendAction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class FrontendAction {
112112
bool runPrescan();
113113
// Parse the current input file. Return False if fatal errors are reported,
114114
// True otherwise.
115-
bool runParse();
115+
bool runParse(bool emitMessages);
116116
// Run semantic checks for the current input file. Return False if fatal
117117
// errors are reported, True otherwise.
118118
bool runSemanticChecks();

flang/include/flang/Semantics/semantics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ class Semantics {
312312
return context_.FindScope(where);
313313
}
314314
bool AnyFatalError() const { return context_.AnyFatalError(); }
315-
void EmitMessages(llvm::raw_ostream &) const;
315+
void EmitMessages(llvm::raw_ostream &);
316316
void DumpSymbols(llvm::raw_ostream &);
317317
void DumpSymbolsSources(llvm::raw_ostream &) const;
318318

flang/lib/Frontend/FrontendAction.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ bool FrontendAction::runPrescan() {
153153
return !reportFatalScanningErrors();
154154
}
155155

156-
bool FrontendAction::runParse() {
156+
bool FrontendAction::runParse(bool emitMessages) {
157157
CompilerInstance &ci = this->getInstance();
158158

159159
// Parse. In case of failure, report and return.
@@ -163,9 +163,11 @@ bool FrontendAction::runParse() {
163163
return false;
164164
}
165165

166-
// Report the diagnostics from getParsing
167-
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
168-
166+
if (emitMessages) {
167+
// Report any non-fatal diagnostics from getParsing now rather than
168+
// combining them with messages from semantics.
169+
ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
170+
}
169171
return true;
170172
}
171173

@@ -174,10 +176,14 @@ bool FrontendAction::runSemanticChecks() {
174176
std::optional<parser::Program> &parseTree{ci.getParsing().parseTree()};
175177
assert(parseTree && "Cannot run semantic checks without a parse tree!");
176178

179+
// Transfer any pending non-fatal messages from parsing to semantics
180+
// so that they are merged and all printed in order.
181+
auto &semanticsCtx{ci.getSemanticsContext()};
182+
semanticsCtx.messages().Annex(std::move(ci.getParsing().messages()));
183+
177184
// Prepare semantics
178185
ci.setSemantics(std::make_unique<Fortran::semantics::Semantics>(
179-
ci.getSemanticsContext(), *parseTree,
180-
ci.getInvocation().getDebugModuleDir()));
186+
semanticsCtx, *parseTree, ci.getInvocation().getDebugModuleDir()));
181187
auto &semantics = ci.getSemantics();
182188

183189
// Run semantic checks
@@ -187,7 +193,7 @@ bool FrontendAction::runSemanticChecks() {
187193
return false;
188194
}
189195

190-
// Report the diagnostics from the semantic checks
196+
// Report the diagnostics from parsing and the semantic checks
191197
semantics.EmitMessages(ci.getSemaOutputStream());
192198

193199
return true;

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ static bool saveMLIRTempFile(const CompilerInvocation &ci,
123123
bool PrescanAction::beginSourceFileAction() { return runPrescan(); }
124124

125125
bool PrescanAndParseAction::beginSourceFileAction() {
126-
return runPrescan() && runParse();
126+
return runPrescan() && runParse(/*emitMessages=*/true);
127127
}
128128

129129
bool PrescanAndSemaAction::beginSourceFileAction() {
130-
return runPrescan() && runParse() && runSemanticChecks() &&
131-
generateRtTypeTables();
130+
return runPrescan() && runParse(/*emitMessages=*/false) &&
131+
runSemanticChecks() && generateRtTypeTables();
132132
}
133133

134134
bool PrescanAndSemaDebugAction::beginSourceFileAction() {
@@ -137,8 +137,8 @@ bool PrescanAndSemaDebugAction::beginSourceFileAction() {
137137
// from exiting early (i.e. in the presence of semantic errors). We should
138138
// never do this in actions intended for end-users or otherwise regular
139139
// compiler workflows!
140-
return runPrescan() && runParse() && (runSemanticChecks() || true) &&
141-
(generateRtTypeTables() || true);
140+
return runPrescan() && runParse(/*emitMessages=*/false) &&
141+
(runSemanticChecks() || true) && (generateRtTypeTables() || true);
142142
}
143143

144144
static void addDependentLibs(mlir::ModuleOp &mlirModule, CompilerInstance &ci) {
@@ -275,8 +275,8 @@ bool CodeGenAction::beginSourceFileAction() {
275275
ci.getDiagnostics().Report(diagID);
276276
return false;
277277
}
278-
bool res = runPrescan() && runParse() && runSemanticChecks() &&
279-
generateRtTypeTables();
278+
bool res = runPrescan() && runParse(/*emitMessages=*/false) &&
279+
runSemanticChecks() && generateRtTypeTables();
280280
if (!res)
281281
return res;
282282

flang/lib/Semantics/semantics.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,10 @@ bool Semantics::Perform() {
593593
ModFileWriter{context_}.WriteAll();
594594
}
595595

596-
void Semantics::EmitMessages(llvm::raw_ostream &os) const {
596+
void Semantics::EmitMessages(llvm::raw_ostream &os) {
597+
// Resolve the CharBlock locations of the Messages to ProvenanceRanges
598+
// so messages from parsing and semantics are intermixed in source order.
599+
context_.messages().ResolveProvenances(context_.allCookedSources());
597600
context_.messages().Emit(os, context_.allCookedSources());
598601
}
599602

flang/test/Driver/message-merging.f90

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
!RUN: %flang -fsyntax-only -pedantic -I %S/Inputs/ %s 2>&1 | FileCheck %s
2+
!CHECK: warning: SAVE attribute was already specified on 'x'
3+
!CHECK: portability: #include: extra stuff ignored after file name
4+
save x
5+
save x
6+
#include <empty.h> crud after header name
7+
end

flang/tools/bbc/bbc.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,17 +289,20 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
289289

290290
// parse the input Fortran
291291
parsing.Parse(llvm::outs());
292-
parsing.messages().Emit(llvm::errs(), parsing.allCooked());
293292
if (!parsing.consumedWholeFile()) {
293+
parsing.messages().Emit(llvm::errs(), parsing.allCooked());
294294
parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
295295
"parser FAIL (final position)",
296296
"error: ", llvm::raw_ostream::RED);
297297
return mlir::failure();
298-
}
299-
if ((!parsing.messages().empty() && (parsing.messages().AnyFatalError())) ||
300-
!parsing.parseTree().has_value()) {
298+
} else if ((!parsing.messages().empty() &&
299+
(parsing.messages().AnyFatalError())) ||
300+
!parsing.parseTree().has_value()) {
301+
parsing.messages().Emit(llvm::errs(), parsing.allCooked());
301302
llvm::errs() << programPrefix << "could not parse " << path << '\n';
302303
return mlir::failure();
304+
} else {
305+
semanticsContext.messages().Annex(std::move(parsing.messages()));
303306
}
304307

305308
// run semantics

0 commit comments

Comments
 (0)