[flang] Add nonfatal message classes

F18 presently has fatal and non-fatal diagnostic messages.  We'd like
to make non-fatal warnings stand out better in the output of the compiler.

This will turn out to be a large change that affects many files.
This patch is just the first part.  It converts a Boolean isFatal_ data
member of the message classes into a severity code, and defines four
of these codes (Error, Warning, Portability, and a catch-all Other).

Later patches will result from sweeping over the parser and semantics,
changing most non-fatal diagnostic messages into warnings and portability
notes.

Differential Revision: https://reviews.llvm.org/D121228
This commit is contained in:
Peter Klausler 2022-03-07 09:23:21 -08:00
parent 1712254b3f
commit 2895771faf
8 changed files with 72 additions and 35 deletions

View File

@ -133,10 +133,20 @@ indicators within the parser and in the parse tree.
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

View File

@ -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 @@ class MessageFormattedText {
public:
template <typename... A>
MessageFormattedText(const MessageFixedText &text, A &&...x)
: isFatal_{text.isFatal()} {
: severity_{text.severity()} {
Format(&text, Convert(std::forward<A>(x))...);
}
MessageFormattedText(const MessageFormattedText &) = default;
@ -77,7 +88,8 @@ public:
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 @@ private:
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<std::string> conversions_; // preserves created strings
};
@ -186,6 +198,7 @@ public:
bool SortBefore(const Message &that) const;
bool IsFatal() const;
Severity severity() const;
std::string ToString() const;
std::optional<ProvenanceRange> GetProvenanceRange(
const AllCookedSources &) const;

View File

@ -155,12 +155,14 @@ bool Message::SortBefore(const Message &that) const {
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 @@ void Message::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
bool echoSourceLine) const {
std::optional<ProvenanceRange> 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()};

View File

@ -38,7 +38,8 @@ bool FormatErrorReporter::Say(const common::FormatMessage &msg) {
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

View File

@ -946,7 +946,8 @@ Scope *ModFileReader::Read(const SourceName &name,
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;

View File

@ -44,10 +44,10 @@ Symbol &Resolve(const parser::Name &name, Symbol &symbol) {
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 @@ bool EquivalenceSets::CheckObject(const parser::Name &name) {
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'"

View File

@ -44,9 +44,9 @@ class SemanticsContext;
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 &);

View File

@ -6654,9 +6654,9 @@ Symbol &ModuleVisitor::SetAccess(
// 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);