From 01d00e2991fca139fa0bc3a95bbe6cd9fd18aeb6 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Tue, 30 Sep 2025 08:34:59 -0700 Subject: [PATCH] [flang] Improve presentation of errors after last source line We don't emit source file names or line numbers for error messages at EOF. Detect these and handle them a little better, pointing at the newline at the end of the last source line instead. --- flang/include/flang/Parser/message.h | 2 ++ flang/lib/Parser/basic-parsers.h | 2 +- flang/lib/Parser/message.cpp | 19 ++++++++++++++++++- flang/test/Parser/recovery08.f90 | 11 +++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 flang/test/Parser/recovery08.f90 diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h index 7da9e12999db1..224263e4be860 100644 --- a/flang/include/flang/Parser/message.h +++ b/flang/include/flang/Parser/message.h @@ -65,6 +65,8 @@ class MessageFixedText { return severity_ == Severity::Error || severity_ == Severity::Todo; } + static const MessageFixedText endOfFileMessage; // "end of file"_err_en_US + private: CharBlock text_; Severity severity_{Severity::None}; diff --git a/flang/lib/Parser/basic-parsers.h b/flang/lib/Parser/basic-parsers.h index 7e69d41debfcd..46d5168c80fe7 100644 --- a/flang/lib/Parser/basic-parsers.h +++ b/flang/lib/Parser/basic-parsers.h @@ -828,7 +828,7 @@ struct NextCh { if (std::optional result{state.GetNextChar()}) { return result; } - state.Say("end of file"_err_en_US); + state.Say(MessageFixedText::endOfFileMessage); return std::nullopt; } }; diff --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp index 2a8101dd0b810..2c4f930c0b088 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 Message::GetProvenanceRange( const AllCookedSources &allCooked) const { return common::visit( common::visitors{ - [&](CharBlock cb) { return allCooked.GetProvenanceRange(cb); }, + [&](CharBlock cb) -> std::optional { + if (auto pr{allCooked.GetProvenanceRange(cb)}) { + return pr; + } else if (const auto *fixed{std::get_if(&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_); diff --git a/flang/test/Parser/recovery08.f90 b/flang/test/Parser/recovery08.f90 new file mode 100644 index 0000000000000..978e42bab9344 --- /dev/null +++ b/flang/test/Parser/recovery08.f90 @@ -0,0 +1,11 @@ +! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s +! CHECK: error: end of file +! CHECK: ^ +! CHECK: in the context: END PROGRAM statement +! CHECK: in the context: main program + + integer :: i + + ! Add empty lines for emphasis + + i = 5