164ab3302SCarolineConcatto //===-- lib/Parser/message.cpp --------------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto
964ab3302SCarolineConcatto #include "flang/Parser/message.h"
1064ab3302SCarolineConcatto #include "flang/Common/idioms.h"
1164ab3302SCarolineConcatto #include "flang/Parser/char-set.h"
128670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h"
1364ab3302SCarolineConcatto #include <algorithm>
1464ab3302SCarolineConcatto #include <cstdarg>
1564ab3302SCarolineConcatto #include <cstddef>
1664ab3302SCarolineConcatto #include <cstdio>
1764ab3302SCarolineConcatto #include <cstring>
1864ab3302SCarolineConcatto #include <string>
1964ab3302SCarolineConcatto #include <vector>
2064ab3302SCarolineConcatto
2164ab3302SCarolineConcatto namespace Fortran::parser {
2264ab3302SCarolineConcatto
operator <<(llvm::raw_ostream & o,const MessageFixedText & t)238670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const MessageFixedText &t) {
2464ab3302SCarolineConcatto std::size_t n{t.text().size()};
2564ab3302SCarolineConcatto for (std::size_t j{0}; j < n; ++j) {
2664ab3302SCarolineConcatto o << t.text()[j];
2764ab3302SCarolineConcatto }
2864ab3302SCarolineConcatto return o;
2964ab3302SCarolineConcatto }
3064ab3302SCarolineConcatto
Format(const MessageFixedText * text,...)3164ab3302SCarolineConcatto void MessageFormattedText::Format(const MessageFixedText *text, ...) {
3264ab3302SCarolineConcatto const char *p{text->text().begin()};
3364ab3302SCarolineConcatto std::string asString;
3464ab3302SCarolineConcatto if (*text->text().end() != '\0') {
3564ab3302SCarolineConcatto // not NUL-terminated
3664ab3302SCarolineConcatto asString = text->text().NULTerminatedToString();
3764ab3302SCarolineConcatto p = asString.c_str();
3864ab3302SCarolineConcatto }
3964ab3302SCarolineConcatto va_list ap;
4064ab3302SCarolineConcatto va_start(ap, text);
4135249cb7SIvan Zhechev #ifdef _MSC_VER
4235249cb7SIvan Zhechev // Microsoft has a separate function for "positional arguments", which is
4335249cb7SIvan Zhechev // used in some messages.
4435249cb7SIvan Zhechev int need{_vsprintf_p(nullptr, 0, p, ap)};
4535249cb7SIvan Zhechev #else
4664ab3302SCarolineConcatto int need{vsnprintf(nullptr, 0, p, ap)};
4735249cb7SIvan Zhechev #endif
4835249cb7SIvan Zhechev
4964ab3302SCarolineConcatto CHECK(need >= 0);
5064ab3302SCarolineConcatto char *buffer{
5164ab3302SCarolineConcatto static_cast<char *>(std::malloc(static_cast<std::size_t>(need) + 1))};
5264ab3302SCarolineConcatto CHECK(buffer);
5364ab3302SCarolineConcatto va_end(ap);
5464ab3302SCarolineConcatto va_start(ap, text);
5535249cb7SIvan Zhechev #ifdef _MSC_VER
5635249cb7SIvan Zhechev // Use positional argument variant of printf.
5735249cb7SIvan Zhechev int need2{_vsprintf_p(buffer, need + 1, p, ap)};
5835249cb7SIvan Zhechev #else
5964ab3302SCarolineConcatto int need2{vsnprintf(buffer, need + 1, p, ap)};
6035249cb7SIvan Zhechev #endif
6164ab3302SCarolineConcatto CHECK(need2 == need);
6264ab3302SCarolineConcatto va_end(ap);
6364ab3302SCarolineConcatto string_ = buffer;
6464ab3302SCarolineConcatto std::free(buffer);
6564ab3302SCarolineConcatto conversions_.clear();
6664ab3302SCarolineConcatto }
6764ab3302SCarolineConcatto
Convert(const std::string & s)6864ab3302SCarolineConcatto const char *MessageFormattedText::Convert(const std::string &s) {
6964ab3302SCarolineConcatto conversions_.emplace_front(s);
7064ab3302SCarolineConcatto return conversions_.front().c_str();
7164ab3302SCarolineConcatto }
7264ab3302SCarolineConcatto
Convert(std::string & s)7364ab3302SCarolineConcatto const char *MessageFormattedText::Convert(std::string &s) {
7464ab3302SCarolineConcatto conversions_.emplace_front(s);
7564ab3302SCarolineConcatto return conversions_.front().c_str();
7664ab3302SCarolineConcatto }
7764ab3302SCarolineConcatto
Convert(std::string && s)7864ab3302SCarolineConcatto const char *MessageFormattedText::Convert(std::string &&s) {
7964ab3302SCarolineConcatto conversions_.emplace_front(std::move(s));
8064ab3302SCarolineConcatto return conversions_.front().c_str();
8164ab3302SCarolineConcatto }
8264ab3302SCarolineConcatto
Convert(CharBlock x)8364ab3302SCarolineConcatto const char *MessageFormattedText::Convert(CharBlock x) {
8464ab3302SCarolineConcatto return Convert(x.ToString());
8564ab3302SCarolineConcatto }
8664ab3302SCarolineConcatto
ToString() const8764ab3302SCarolineConcatto std::string MessageExpectedText::ToString() const {
88cd03e96fSPeter Klausler return common::visit(
8964ab3302SCarolineConcatto common::visitors{
9064ab3302SCarolineConcatto [](CharBlock cb) {
9164ab3302SCarolineConcatto return MessageFormattedText("expected '%s'"_err_en_US, cb)
9264ab3302SCarolineConcatto .MoveString();
9364ab3302SCarolineConcatto },
9464ab3302SCarolineConcatto [](const SetOfChars &set) {
9564ab3302SCarolineConcatto SetOfChars expect{set};
9664ab3302SCarolineConcatto if (expect.Has('\n')) {
9764ab3302SCarolineConcatto expect = expect.Difference('\n');
9864ab3302SCarolineConcatto if (expect.empty()) {
9964ab3302SCarolineConcatto return "expected end of line"_err_en_US.text().ToString();
10064ab3302SCarolineConcatto } else {
10164ab3302SCarolineConcatto std::string s{expect.ToString()};
10264ab3302SCarolineConcatto if (s.size() == 1) {
10364ab3302SCarolineConcatto return MessageFormattedText(
10464ab3302SCarolineConcatto "expected end of line or '%s'"_err_en_US, s)
10564ab3302SCarolineConcatto .MoveString();
10664ab3302SCarolineConcatto } else {
10764ab3302SCarolineConcatto return MessageFormattedText(
10864ab3302SCarolineConcatto "expected end of line or one of '%s'"_err_en_US, s)
10964ab3302SCarolineConcatto .MoveString();
11064ab3302SCarolineConcatto }
11164ab3302SCarolineConcatto }
11264ab3302SCarolineConcatto }
11364ab3302SCarolineConcatto std::string s{expect.ToString()};
11464ab3302SCarolineConcatto if (s.size() != 1) {
11564ab3302SCarolineConcatto return MessageFormattedText("expected one of '%s'"_err_en_US, s)
11664ab3302SCarolineConcatto .MoveString();
11764ab3302SCarolineConcatto } else {
11864ab3302SCarolineConcatto return MessageFormattedText("expected '%s'"_err_en_US, s)
11964ab3302SCarolineConcatto .MoveString();
12064ab3302SCarolineConcatto }
12164ab3302SCarolineConcatto },
12264ab3302SCarolineConcatto },
12364ab3302SCarolineConcatto u_);
12464ab3302SCarolineConcatto }
12564ab3302SCarolineConcatto
Merge(const MessageExpectedText & that)12664ab3302SCarolineConcatto bool MessageExpectedText::Merge(const MessageExpectedText &that) {
127cd03e96fSPeter Klausler return common::visit(common::visitors{
12864ab3302SCarolineConcatto [](SetOfChars &s1, const SetOfChars &s2) {
12964ab3302SCarolineConcatto s1 = s1.Union(s2);
13064ab3302SCarolineConcatto return true;
13164ab3302SCarolineConcatto },
13264ab3302SCarolineConcatto [](const auto &, const auto &) { return false; },
13364ab3302SCarolineConcatto },
13464ab3302SCarolineConcatto u_, that.u_);
13564ab3302SCarolineConcatto }
13664ab3302SCarolineConcatto
SortBefore(const Message & that) const13764ab3302SCarolineConcatto bool Message::SortBefore(const Message &that) const {
13864ab3302SCarolineConcatto // Messages from prescanning have ProvenanceRange values for their locations,
13964ab3302SCarolineConcatto // while messages from later phases have CharBlock values, since the
14064ab3302SCarolineConcatto // conversion of cooked source stream locations to provenances is not
14164ab3302SCarolineConcatto // free and needs to be deferred, and many messages created during parsing
14264ab3302SCarolineConcatto // are speculative. Messages with ProvenanceRange locations are ordered
14364ab3302SCarolineConcatto // before others for sorting.
144cd03e96fSPeter Klausler return common::visit(
14564ab3302SCarolineConcatto common::visitors{
14664ab3302SCarolineConcatto [](CharBlock cb1, CharBlock cb2) {
14764ab3302SCarolineConcatto return cb1.begin() < cb2.begin();
14864ab3302SCarolineConcatto },
14964ab3302SCarolineConcatto [](CharBlock, const ProvenanceRange &) { return false; },
15064ab3302SCarolineConcatto [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {
15164ab3302SCarolineConcatto return pr1.start() < pr2.start();
15264ab3302SCarolineConcatto },
15364ab3302SCarolineConcatto [](const ProvenanceRange &, CharBlock) { return true; },
15464ab3302SCarolineConcatto },
15564ab3302SCarolineConcatto location_, that.location_);
15664ab3302SCarolineConcatto }
15764ab3302SCarolineConcatto
IsFatal() const158*d1344422SPeter Steinfeld bool Message::IsFatal() const {
159*d1344422SPeter Steinfeld return severity() == Severity::Error || severity() == Severity::Todo;
160*d1344422SPeter Steinfeld }
1612895771fSPeter Klausler
severity() const1622895771fSPeter Klausler Severity Message::severity() const {
163cd03e96fSPeter Klausler return common::visit(
16464ab3302SCarolineConcatto common::visitors{
1652895771fSPeter Klausler [](const MessageExpectedText &) { return Severity::Error; },
1662895771fSPeter Klausler [](const MessageFixedText &x) { return x.severity(); },
1672895771fSPeter Klausler [](const MessageFormattedText &x) { return x.severity(); },
16864ab3302SCarolineConcatto },
16964ab3302SCarolineConcatto text_);
17064ab3302SCarolineConcatto }
17164ab3302SCarolineConcatto
set_severity(Severity severity)172ef141aecSPeter Klausler Message &Message::set_severity(Severity severity) {
173cd03e96fSPeter Klausler common::visit(
174ef141aecSPeter Klausler common::visitors{
175ef141aecSPeter Klausler [](const MessageExpectedText &) {},
176ef141aecSPeter Klausler [severity](MessageFixedText &x) { x.set_severity(severity); },
177ef141aecSPeter Klausler [severity](MessageFormattedText &x) { x.set_severity(severity); },
178ef141aecSPeter Klausler },
179ef141aecSPeter Klausler text_);
180ef141aecSPeter Klausler return *this;
181ef141aecSPeter Klausler }
182ef141aecSPeter Klausler
ToString() const18364ab3302SCarolineConcatto std::string Message::ToString() const {
184cd03e96fSPeter Klausler return common::visit(
18564ab3302SCarolineConcatto common::visitors{
18664ab3302SCarolineConcatto [](const MessageFixedText &t) {
18764ab3302SCarolineConcatto return t.text().NULTerminatedToString();
18864ab3302SCarolineConcatto },
18964ab3302SCarolineConcatto [](const MessageFormattedText &t) { return t.string(); },
19064ab3302SCarolineConcatto [](const MessageExpectedText &e) { return e.ToString(); },
19164ab3302SCarolineConcatto },
19264ab3302SCarolineConcatto text_);
19364ab3302SCarolineConcatto }
19464ab3302SCarolineConcatto
ResolveProvenances(const AllCookedSources & allCooked)19592a54197Speter klausler void Message::ResolveProvenances(const AllCookedSources &allCooked) {
19664ab3302SCarolineConcatto if (CharBlock * cb{std::get_if<CharBlock>(&location_)}) {
19764ab3302SCarolineConcatto if (std::optional<ProvenanceRange> resolved{
19892a54197Speter klausler allCooked.GetProvenanceRange(*cb)}) {
19964ab3302SCarolineConcatto location_ = *resolved;
20064ab3302SCarolineConcatto }
20164ab3302SCarolineConcatto }
20264ab3302SCarolineConcatto if (Message * attachment{attachment_.get()}) {
20392a54197Speter klausler attachment->ResolveProvenances(allCooked);
20464ab3302SCarolineConcatto }
20564ab3302SCarolineConcatto }
20664ab3302SCarolineConcatto
GetProvenanceRange(const AllCookedSources & allCooked) const20764ab3302SCarolineConcatto std::optional<ProvenanceRange> Message::GetProvenanceRange(
20892a54197Speter klausler const AllCookedSources &allCooked) const {
209cd03e96fSPeter Klausler return common::visit(
21064ab3302SCarolineConcatto common::visitors{
21192a54197Speter klausler [&](CharBlock cb) { return allCooked.GetProvenanceRange(cb); },
21264ab3302SCarolineConcatto [](const ProvenanceRange &pr) { return std::make_optional(pr); },
21364ab3302SCarolineConcatto },
21464ab3302SCarolineConcatto location_);
21564ab3302SCarolineConcatto }
21664ab3302SCarolineConcatto
Prefix(Severity severity)217ef141aecSPeter Klausler static std::string Prefix(Severity severity) {
218ef141aecSPeter Klausler switch (severity) {
2192895771fSPeter Klausler case Severity::Error:
220ef141aecSPeter Klausler return "error: ";
2212895771fSPeter Klausler case Severity::Warning:
222ef141aecSPeter Klausler return "warning: ";
2232895771fSPeter Klausler case Severity::Portability:
224ef141aecSPeter Klausler return "portability: ";
225ef141aecSPeter Klausler case Severity::Because:
226ef141aecSPeter Klausler return "because: ";
227ef141aecSPeter Klausler case Severity::Context:
228ef141aecSPeter Klausler return "in the context: ";
229*d1344422SPeter Steinfeld case Severity::Todo:
230*d1344422SPeter Steinfeld return "error: not yet implemented: ";
2312895771fSPeter Klausler case Severity::None:
2322895771fSPeter Klausler break;
23364ab3302SCarolineConcatto }
234ef141aecSPeter Klausler return "";
235ef141aecSPeter Klausler }
236ef141aecSPeter Klausler
Emit(llvm::raw_ostream & o,const AllCookedSources & allCooked,bool echoSourceLine) const237ef141aecSPeter Klausler void Message::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
238ef141aecSPeter Klausler bool echoSourceLine) const {
239ef141aecSPeter Klausler std::optional<ProvenanceRange> provenanceRange{GetProvenanceRange(allCooked)};
24092a54197Speter klausler const AllSources &sources{allCooked.allSources()};
241ef141aecSPeter Klausler sources.EmitMessage(
242ef141aecSPeter Klausler o, provenanceRange, Prefix(severity()) + ToString(), echoSourceLine);
243641ede93Speter klausler bool isContext{attachmentIsContext_};
24464ab3302SCarolineConcatto for (const Message *attachment{attachment_.get()}; attachment;
24564ab3302SCarolineConcatto attachment = attachment->attachment_.get()) {
246ef141aecSPeter Klausler sources.EmitMessage(o, attachment->GetProvenanceRange(allCooked),
247ef141aecSPeter Klausler Prefix(isContext ? Severity::Context : attachment->severity()) +
248ef141aecSPeter Klausler attachment->ToString(),
249ef141aecSPeter Klausler echoSourceLine);
25064ab3302SCarolineConcatto }
25164ab3302SCarolineConcatto }
25264ab3302SCarolineConcatto
2535a9497d6SPeter Steinfeld // Messages are equal if they're for the same location and text, and the user
2545a9497d6SPeter Steinfeld // visible aspects of their attachments are the same
operator ==(const Message & that) const2555a9497d6SPeter Steinfeld bool Message::operator==(const Message &that) const {
256ef141aecSPeter Klausler if (!AtSameLocation(that) || ToString() != that.ToString() ||
257ef141aecSPeter Klausler severity() != that.severity() ||
258ef141aecSPeter Klausler attachmentIsContext_ != that.attachmentIsContext_) {
2595a9497d6SPeter Steinfeld return false;
2605a9497d6SPeter Steinfeld }
2615a9497d6SPeter Steinfeld const Message *thatAttachment{that.attachment_.get()};
2625a9497d6SPeter Steinfeld for (const Message *attachment{attachment_.get()}; attachment;
2635a9497d6SPeter Steinfeld attachment = attachment->attachment_.get()) {
264ef141aecSPeter Klausler if (!thatAttachment || !attachment->AtSameLocation(*thatAttachment) ||
265ef141aecSPeter Klausler attachment->ToString() != thatAttachment->ToString() ||
266ef141aecSPeter Klausler attachment->severity() != thatAttachment->severity()) {
2675a9497d6SPeter Steinfeld return false;
2685a9497d6SPeter Steinfeld }
2695a9497d6SPeter Steinfeld thatAttachment = thatAttachment->attachment_.get();
2705a9497d6SPeter Steinfeld }
271ef141aecSPeter Klausler return !thatAttachment;
2725a9497d6SPeter Steinfeld }
2735a9497d6SPeter Steinfeld
Merge(const Message & that)27464ab3302SCarolineConcatto bool Message::Merge(const Message &that) {
27564ab3302SCarolineConcatto return AtSameLocation(that) &&
27664ab3302SCarolineConcatto (!that.attachment_.get() ||
27764ab3302SCarolineConcatto attachment_.get() == that.attachment_.get()) &&
278cd03e96fSPeter Klausler common::visit(
27964ab3302SCarolineConcatto common::visitors{
28064ab3302SCarolineConcatto [](MessageExpectedText &e1, const MessageExpectedText &e2) {
28164ab3302SCarolineConcatto return e1.Merge(e2);
28264ab3302SCarolineConcatto },
28364ab3302SCarolineConcatto [](const auto &, const auto &) { return false; },
28464ab3302SCarolineConcatto },
28564ab3302SCarolineConcatto text_, that.text_);
28664ab3302SCarolineConcatto }
28764ab3302SCarolineConcatto
Attach(Message * m)28864ab3302SCarolineConcatto Message &Message::Attach(Message *m) {
28964ab3302SCarolineConcatto if (!attachment_) {
29064ab3302SCarolineConcatto attachment_ = m;
29164ab3302SCarolineConcatto } else {
292641ede93Speter klausler if (attachment_->references() > 1) {
293641ede93Speter klausler // Don't attach to a shared context attachment; copy it first.
294641ede93Speter klausler attachment_ = new Message{*attachment_};
295641ede93Speter klausler }
29664ab3302SCarolineConcatto attachment_->Attach(m);
29764ab3302SCarolineConcatto }
29864ab3302SCarolineConcatto return *this;
29964ab3302SCarolineConcatto }
30064ab3302SCarolineConcatto
Attach(std::unique_ptr<Message> && m)30164ab3302SCarolineConcatto Message &Message::Attach(std::unique_ptr<Message> &&m) {
30264ab3302SCarolineConcatto return Attach(m.release());
30364ab3302SCarolineConcatto }
30464ab3302SCarolineConcatto
AtSameLocation(const Message & that) const30564ab3302SCarolineConcatto bool Message::AtSameLocation(const Message &that) const {
306cd03e96fSPeter Klausler return common::visit(
30764ab3302SCarolineConcatto common::visitors{
30864ab3302SCarolineConcatto [](CharBlock cb1, CharBlock cb2) {
30964ab3302SCarolineConcatto return cb1.begin() == cb2.begin();
31064ab3302SCarolineConcatto },
31164ab3302SCarolineConcatto [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) {
31264ab3302SCarolineConcatto return pr1.start() == pr2.start();
31364ab3302SCarolineConcatto },
31464ab3302SCarolineConcatto [](const auto &, const auto &) { return false; },
31564ab3302SCarolineConcatto },
31664ab3302SCarolineConcatto location_, that.location_);
31764ab3302SCarolineConcatto }
31864ab3302SCarolineConcatto
Merge(const Message & msg)31964ab3302SCarolineConcatto bool Messages::Merge(const Message &msg) {
32064ab3302SCarolineConcatto if (msg.IsMergeable()) {
32164ab3302SCarolineConcatto for (auto &m : messages_) {
32264ab3302SCarolineConcatto if (m.Merge(msg)) {
32364ab3302SCarolineConcatto return true;
32464ab3302SCarolineConcatto }
32564ab3302SCarolineConcatto }
32664ab3302SCarolineConcatto }
32764ab3302SCarolineConcatto return false;
32864ab3302SCarolineConcatto }
32964ab3302SCarolineConcatto
Merge(Messages && that)33064ab3302SCarolineConcatto void Messages::Merge(Messages &&that) {
33164ab3302SCarolineConcatto if (messages_.empty()) {
33264ab3302SCarolineConcatto *this = std::move(that);
33364ab3302SCarolineConcatto } else {
33464ab3302SCarolineConcatto while (!that.messages_.empty()) {
33564ab3302SCarolineConcatto if (Merge(that.messages_.front())) {
33664ab3302SCarolineConcatto that.messages_.pop_front();
33764ab3302SCarolineConcatto } else {
338cc575dd2Speter klausler auto next{that.messages_.begin()};
339cc575dd2Speter klausler ++next;
340cc575dd2Speter klausler messages_.splice(
341cc575dd2Speter klausler messages_.end(), that.messages_, that.messages_.begin(), next);
34264ab3302SCarolineConcatto }
34364ab3302SCarolineConcatto }
34464ab3302SCarolineConcatto }
34564ab3302SCarolineConcatto }
34664ab3302SCarolineConcatto
Copy(const Messages & that)34764ab3302SCarolineConcatto void Messages::Copy(const Messages &that) {
34864ab3302SCarolineConcatto for (const Message &m : that.messages_) {
34964ab3302SCarolineConcatto Message copy{m};
35064ab3302SCarolineConcatto Say(std::move(copy));
35164ab3302SCarolineConcatto }
35264ab3302SCarolineConcatto }
35364ab3302SCarolineConcatto
ResolveProvenances(const AllCookedSources & allCooked)35492a54197Speter klausler void Messages::ResolveProvenances(const AllCookedSources &allCooked) {
35564ab3302SCarolineConcatto for (Message &m : messages_) {
35692a54197Speter klausler m.ResolveProvenances(allCooked);
35764ab3302SCarolineConcatto }
35864ab3302SCarolineConcatto }
35964ab3302SCarolineConcatto
Emit(llvm::raw_ostream & o,const AllCookedSources & allCooked,bool echoSourceLines) const36092a54197Speter klausler void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked,
3618670e499SCaroline Concatto bool echoSourceLines) const {
36264ab3302SCarolineConcatto std::vector<const Message *> sorted;
36364ab3302SCarolineConcatto for (const auto &msg : messages_) {
36464ab3302SCarolineConcatto sorted.push_back(&msg);
36564ab3302SCarolineConcatto }
36664ab3302SCarolineConcatto std::stable_sort(sorted.begin(), sorted.end(),
36764ab3302SCarolineConcatto [](const Message *x, const Message *y) { return x->SortBefore(*y); });
3685a9497d6SPeter Steinfeld const Message *lastMsg{nullptr};
36964ab3302SCarolineConcatto for (const Message *msg : sorted) {
3705a9497d6SPeter Steinfeld if (lastMsg && *msg == *lastMsg) {
3715a9497d6SPeter Steinfeld // Don't emit two identical messages for the same location
3725a9497d6SPeter Steinfeld continue;
3735a9497d6SPeter Steinfeld }
37492a54197Speter klausler msg->Emit(o, allCooked, echoSourceLines);
3755a9497d6SPeter Steinfeld lastMsg = msg;
37664ab3302SCarolineConcatto }
37764ab3302SCarolineConcatto }
37864ab3302SCarolineConcatto
AttachTo(Message & msg,std::optional<Severity> severity)379ef141aecSPeter Klausler void Messages::AttachTo(Message &msg, std::optional<Severity> severity) {
38064ab3302SCarolineConcatto for (Message &m : messages_) {
381ef141aecSPeter Klausler Message m2{std::move(m)};
382ef141aecSPeter Klausler if (severity) {
383ef141aecSPeter Klausler m2.set_severity(*severity);
384ef141aecSPeter Klausler }
385ef141aecSPeter Klausler msg.Attach(std::move(m2));
38664ab3302SCarolineConcatto }
38764ab3302SCarolineConcatto messages_.clear();
38864ab3302SCarolineConcatto }
38964ab3302SCarolineConcatto
AnyFatalError() const39064ab3302SCarolineConcatto bool Messages::AnyFatalError() const {
39164ab3302SCarolineConcatto for (const auto &msg : messages_) {
39264ab3302SCarolineConcatto if (msg.IsFatal()) {
39364ab3302SCarolineConcatto return true;
39464ab3302SCarolineConcatto }
39564ab3302SCarolineConcatto }
39664ab3302SCarolineConcatto return false;
39764ab3302SCarolineConcatto }
3981f879005STim Keith } // namespace Fortran::parser
399