summaryrefslogtreecommitdiff
path: root/flang/lib/Parser/message.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Parser/message.cpp')
-rw-r--r--flang/lib/Parser/message.cpp43
1 files changed, 38 insertions, 5 deletions
diff --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp
index 2a8101dd0b81..cfcd08b0861e 100644
--- a/flang/lib/Parser/message.cpp
+++ b/flang/lib/Parser/message.cpp
@@ -21,6 +21,10 @@
namespace Fortran::parser {
+// The nextCh parser emits this, and Message::GetProvenanceRange() looks for it.
+const MessageFixedText MessageFixedText::endOfFileMessage{
+ "end of file"_err_en_US};
+
llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const MessageFixedText &t) {
std::size_t n{t.text().size()};
for (std::size_t j{0}; j < n; ++j) {
@@ -232,7 +236,20 @@ std::optional<ProvenanceRange> Message::GetProvenanceRange(
const AllCookedSources &allCooked) const {
return common::visit(
common::visitors{
- [&](CharBlock cb) { return allCooked.GetProvenanceRange(cb); },
+ [&](CharBlock cb) -> std::optional<ProvenanceRange> {
+ if (auto pr{allCooked.GetProvenanceRange(cb)}) {
+ return pr;
+ } else if (const auto *fixed{std::get_if<MessageFixedText>(&text_)};
+ fixed &&
+ fixed->text() == MessageFixedText::endOfFileMessage.text() &&
+ cb.begin() && cb.size() == 1) {
+ // Failure from "nextCh" due to reaching EOF. Back up one byte
+ // to the terminal newline so that the output looks better.
+ return allCooked.GetProvenanceRange(CharBlock{cb.begin() - 1, 1});
+ } else {
+ return std::nullopt;
+ }
+ },
[](const ProvenanceRange &pr) { return std::make_optional(pr); },
},
location_);
@@ -460,15 +477,31 @@ void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
}
std::stable_sort(sorted.begin(), sorted.end(),
[](const Message *x, const Message *y) { return x->SortBefore(*y); });
- const Message *lastMsg{nullptr};
+ std::vector<const Message *> msgsWithLastLocation;
std::size_t errorsEmitted{0};
for (const Message *msg : sorted) {
- if (lastMsg && *msg == *lastMsg) {
- // Don't emit two identical messages for the same location
+ bool shouldSkipMsg{false};
+ // Don't emit two identical messages for the same location.
+ // At the same location, messages are sorted by the order they were
+ // added to the Messages buffer, which is a decent proxy for the
+ // causality of the messages.
+ if (!msgsWithLastLocation.empty()) {
+ if (msgsWithLastLocation[0]->AtSameLocation(*msg)) {
+ for (const Message *msgAtThisLocation : msgsWithLastLocation) {
+ if (*msg == *msgAtThisLocation) {
+ shouldSkipMsg = true; // continue loop over sorted messages
+ break;
+ }
+ }
+ } else {
+ msgsWithLastLocation.clear();
+ }
+ }
+ if (shouldSkipMsg) {
continue;
}
+ msgsWithLastLocation.push_back(msg);
msg->Emit(o, allCooked, echoSourceLines, hintFlagPtr);
- lastMsg = msg;
if (warningsAreErrors || msg->IsFatal()) {
++errorsEmitted;
}