diff --git a/flang/docs/Parsing.md b/flang/docs/Parsing.md --- a/flang/docs/Parsing.md +++ b/flang/docs/Parsing.md @@ -133,10 +133,20 @@ Message texts, and snprintf-like formatting strings for constructing messages, are instantiated in the various components of the parser with -C++ user defined character literals tagged with `_err_en_US` and `_en_US` -(signifying fatality and language, with the default being the dialect of -English used in the United States) so that they may be easily identified -for localization. As described above, messages are associated with +C++ user defined character literals tagged with `_err_en_US`, `_warn_en_US`, +`port_en_US`, and `_en_US` to signify severity and language; the default +language is the dialect of English used in the United States. + +All "fatal" errors that do not immediately abort compilation but do +prevent the generation of binary and module files are `_err_en_US`. +Warnings about detected flaws in the program that probably indicate +problems worth attention are `_warn_en_US`. +Non-conforming extensions, legacy features, and obsolescent or deleted +features will raise `_port_en_US` messages when those are enabled. +Other messages have a simple `_en_US` suffix, including all messages +that are explanatory attachments. + +As described above, messages are associated with source code positions by means of provenance values. ## The Parse Tree diff --git a/flang/include/flang/Parser/message.h b/flang/include/flang/Parser/message.h --- a/flang/include/flang/Parser/message.h +++ b/flang/include/flang/Parser/message.h @@ -29,34 +29,45 @@ namespace Fortran::parser { -// Use "..."_err_en_US and "..."_en_US literals to define the static -// text and fatality of a message. +// Use "..."_err_en_US, "..."_warn_en_US, and "..."_en_US literals to define +// the static text and fatality of a message. +enum class Severity { Error, Warning, Portability, None }; + class MessageFixedText { public: + constexpr MessageFixedText() {} constexpr MessageFixedText( - const char str[], std::size_t n, bool isFatal = false) - : text_{str, n}, isFatal_{isFatal} {} + const char str[], std::size_t n, Severity severity = Severity::None) + : text_{str, n}, severity_{severity} {} constexpr MessageFixedText(const MessageFixedText &) = default; constexpr MessageFixedText(MessageFixedText &&) = default; constexpr MessageFixedText &operator=(const MessageFixedText &) = default; constexpr MessageFixedText &operator=(MessageFixedText &&) = default; CharBlock text() const { return text_; } - bool isFatal() const { return isFatal_; } + Severity severity() const { return severity_; } + bool isFatal() const { return severity_ == Severity::Error; } private: CharBlock text_; - bool isFatal_{false}; + Severity severity_{Severity::None}; }; inline namespace literals { -constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) { - return MessageFixedText{str, n, false /* not fatal */}; -} - constexpr MessageFixedText operator""_err_en_US( const char str[], std::size_t n) { - return MessageFixedText{str, n, true /* fatal */}; + return MessageFixedText{str, n, Severity::Error}; +} +constexpr MessageFixedText operator""_warn_en_US( + const char str[], std::size_t n) { + return MessageFixedText{str, n, Severity::Warning}; +} +constexpr MessageFixedText operator""_port_en_US( + const char str[], std::size_t n) { + return MessageFixedText{str, n, Severity::Portability}; +} +constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) { + return MessageFixedText{str, n, Severity::None}; } } // namespace literals @@ -69,7 +80,7 @@ public: template MessageFormattedText(const MessageFixedText &text, A &&...x) - : isFatal_{text.isFatal()} { + : severity_{text.severity()} { Format(&text, Convert(std::forward(x))...); } MessageFormattedText(const MessageFormattedText &) = default; @@ -77,7 +88,8 @@ MessageFormattedText &operator=(const MessageFormattedText &) = default; MessageFormattedText &operator=(MessageFormattedText &&) = default; const std::string &string() const { return string_; } - bool isFatal() const { return isFatal_; } + bool isFatal() const { return severity_ == Severity::Error; } + Severity severity() const { return severity_; } std::string MoveString() { return std::move(string_); } private: @@ -104,7 +116,7 @@ std::intmax_t Convert(std::int64_t x) { return x; } std::uintmax_t Convert(std::uint64_t x) { return x; } - bool isFatal_{false}; + Severity severity_; std::string string_; std::forward_list conversions_; // preserves created strings }; @@ -186,6 +198,7 @@ bool SortBefore(const Message &that) const; bool IsFatal() const; + Severity severity() const; std::string ToString() const; std::optional GetProvenanceRange( const AllCookedSources &) const; diff --git a/flang/lib/Parser/message.cpp b/flang/lib/Parser/message.cpp --- a/flang/lib/Parser/message.cpp +++ b/flang/lib/Parser/message.cpp @@ -155,12 +155,14 @@ location_, that.location_); } -bool Message::IsFatal() const { +bool Message::IsFatal() const { return severity() == Severity::Error; } + +Severity Message::severity() const { return std::visit( common::visitors{ - [](const MessageExpectedText &) { return true; }, - [](const MessageFixedText &x) { return x.isFatal(); }, - [](const MessageFormattedText &x) { return x.isFatal(); }, + [](const MessageExpectedText &) { return Severity::Error; }, + [](const MessageFixedText &x) { return x.severity(); }, + [](const MessageFormattedText &x) { return x.severity(); }, }, text_); } @@ -203,8 +205,18 @@ bool echoSourceLine) const { std::optional provenanceRange{GetProvenanceRange(allCooked)}; std::string text; - if (IsFatal()) { - text += "error: "; + switch (severity()) { + case Severity::Error: + text = "error: "; + break; + case Severity::Warning: + text = "warning: "; + break; + case Severity::Portability: + text = "portability: "; + break; + case Severity::None: + break; } text += ToString(); const AllSources &sources{allCooked.allSources()}; diff --git a/flang/lib/Semantics/check-io.cpp b/flang/lib/Semantics/check-io.cpp --- a/flang/lib/Semantics/check-io.cpp +++ b/flang/lib/Semantics/check-io.cpp @@ -38,7 +38,8 @@ return false; } parser::MessageFormattedText text{ - parser::MessageFixedText(msg.text, strlen(msg.text), msg.isError), + parser::MessageFixedText{msg.text, strlen(msg.text), + msg.isError ? parser::Severity::Error : parser::Severity::Warning}, msg.arg}; if (formatCharBlock_.size()) { // The input format is a folded expression. Error markers span the full diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -946,7 +946,8 @@ for (auto &msg : parsing.messages().messages()) { std::string str{msg.ToString()}; Say(name, ancestorName, - parser::MessageFixedText{str.c_str(), str.size()}, path); + parser::MessageFixedText{str.c_str(), str.size(), msg.severity()}, + path); } } return nullptr; diff --git a/flang/lib/Semantics/resolve-names-utils.h b/flang/lib/Semantics/resolve-names-utils.h --- a/flang/lib/Semantics/resolve-names-utils.h +++ b/flang/lib/Semantics/resolve-names-utils.h @@ -44,9 +44,9 @@ Symbol &Resolve(const parser::Name &, Symbol &); Symbol *Resolve(const parser::Name &, Symbol *); -// Create a copy of msg with a new isFatal value. -parser::MessageFixedText WithIsFatal( - const parser::MessageFixedText &msg, bool isFatal); +// Create a copy of msg with a new severity. +parser::MessageFixedText WithSeverity( + const parser::MessageFixedText &msg, parser::Severity); bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &); bool IsLogicalConstant(const SemanticsContext &, const SourceName &); diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp --- a/flang/lib/Semantics/resolve-names-utils.cpp +++ b/flang/lib/Semantics/resolve-names-utils.cpp @@ -44,10 +44,10 @@ return *Resolve(name, &symbol); } -parser::MessageFixedText WithIsFatal( - const parser::MessageFixedText &msg, bool isFatal) { +parser::MessageFixedText WithSeverity( + const parser::MessageFixedText &msg, parser::Severity severity) { return parser::MessageFixedText{ - msg.text().begin(), msg.text().size(), isFatal}; + msg.text().begin(), msg.text().size(), severity}; } bool IsIntrinsicOperator( @@ -576,7 +576,7 @@ return false; // an error has already occurred } currObject_.symbol = name.symbol; - parser::MessageFixedText msg{"", 0}; + parser::MessageFixedText msg; const Symbol &symbol{*name.symbol}; if (symbol.owner().IsDerivedType()) { // C8107 msg = "Derived type component '%s'" diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -6654,9 +6654,9 @@ // PUBLIC/PRIVATE already set: make it a fatal error if it changed Attr prev = attrs.test(Attr::PUBLIC) ? Attr::PUBLIC : Attr::PRIVATE; Say(name, - WithIsFatal( + WithSeverity( "The accessibility of '%s' has already been specified as %s"_en_US, - attr != prev), + attr != prev ? parser::Severity::Error : parser::Severity::Warning), MakeOpName(name), EnumToString(prev)); } else { attrs.set(attr);