diff options
Diffstat (limited to 'flang/lib/Parser/message.cpp')
| -rw-r--r-- | flang/lib/Parser/message.cpp | 43 |
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; } |
