[flang] Clean up messaging: make Say() member function templates more flexible, hide MessageFormattedText instances
Original-commit: flang-compiler/f18@59d774382f Reviewed-on: https://github.com/flang-compiler/f18/pull/165 Tree-same-pre-rewrite: false
This commit is contained in:
parent
27be6855bf
commit
ce231b9559
|
@ -18,6 +18,7 @@
|
|||
#include "../common/enum-set.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../common/indirection.h"
|
||||
#include "../parser/message.h"
|
||||
#include <cinttypes>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
@ -127,5 +128,14 @@ using HostUnsignedInt =
|
|||
// Force availability of copy construction and assignment
|
||||
template<typename A> using CopyableIndirection = common::Indirection<A, true>;
|
||||
|
||||
// Classes that support a Fold(FoldingContext &) member function have the
|
||||
// FoldableTrait set.
|
||||
CLASS_TRAIT(FoldableTrait);
|
||||
struct FoldingContext {
|
||||
parser::ContextualMessages &messages;
|
||||
Rounding rounding{defaultRounding};
|
||||
bool flushDenormalsToZero{false};
|
||||
};
|
||||
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_COMMON_H_
|
||||
|
|
|
@ -383,20 +383,16 @@ auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
|||
static void RealFlagWarnings(
|
||||
FoldingContext &context, const RealFlags &flags, const char *operation) {
|
||||
if (flags.test(RealFlag::Overflow)) {
|
||||
context.messages.Say(
|
||||
parser::MessageFormattedText("overflow on %s"_en_US, operation));
|
||||
context.messages.Say("overflow on %s"_en_US, operation);
|
||||
}
|
||||
if (flags.test(RealFlag::DivideByZero)) {
|
||||
context.messages.Say(parser::MessageFormattedText(
|
||||
"division by zero on %s"_en_US, operation));
|
||||
context.messages.Say("division by zero on %s"_en_US, operation);
|
||||
}
|
||||
if (flags.test(RealFlag::InvalidArgument)) {
|
||||
context.messages.Say(parser::MessageFormattedText(
|
||||
"invalid argument on %s"_en_US, operation));
|
||||
context.messages.Say("invalid argument on %s"_en_US, operation);
|
||||
}
|
||||
if (flags.test(RealFlag::Underflow)) {
|
||||
context.messages.Say(
|
||||
parser::MessageFormattedText("underflow on %s"_en_US, operation));
|
||||
context.messages.Say("underflow on %s"_en_US, operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,6 @@
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
CLASS_TRAIT(FoldableTrait);
|
||||
struct FoldingContext {
|
||||
parser::ContextualMessages &messages;
|
||||
Rounding rounding{defaultRounding};
|
||||
bool flushDenormalsToZero{false};
|
||||
};
|
||||
|
||||
// Helper base classes for packaging subexpressions.
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
|
||||
protected:
|
||||
|
@ -175,11 +168,15 @@ public:
|
|||
Expr(std::int64_t n) : u_{Scalar{n}} {}
|
||||
Expr(std::uint64_t n) : u_{Scalar{n}} {}
|
||||
Expr(int n) : u_{Scalar{n}} {}
|
||||
Expr(const AnyKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
|
||||
Expr(AnyKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{AnyKindIntegerExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(IntegerExpr<K> &&x)
|
||||
: u_{ConvertInteger{AnyKindIntegerExpr{std::move(x)}}} {}
|
||||
Expr(const AnyKindRealExpr &x) : u_{ConvertReal{x}} {}
|
||||
Expr(AnyKindRealExpr &&x) : u_{ConvertReal{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{AnyKindRealExpr{x}}} {}
|
||||
template<int K>
|
||||
|
@ -296,11 +293,15 @@ public:
|
|||
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
Expr(const Scalar &x) : u_{x} {}
|
||||
Expr(const AnyKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
|
||||
Expr(AnyKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{AnyKindIntegerExpr{x}}} {}
|
||||
template<int K>
|
||||
Expr(IntegerExpr<K> &&x)
|
||||
: u_{ConvertInteger{AnyKindIntegerExpr{std::move(x)}}} {}
|
||||
Expr(const AnyKindRealExpr &x) : u_{ConvertReal{x}} {}
|
||||
Expr(AnyKindRealExpr &&x) : u_{ConvertReal{std::move(x)}} {}
|
||||
template<int K>
|
||||
Expr(const RealExpr<K> &x) : u_{ConvertReal{AnyKindRealExpr{x}}} {}
|
||||
template<int K>
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
#include "../common/idioms.h"
|
||||
#include "../parser/char-block.h"
|
||||
#include "../parser/characters.h"
|
||||
#include "../parser/message.h"
|
||||
#include "../semantics/symbol.h"
|
||||
#include <ostream>
|
||||
|
||||
using namespace Fortran::parser::literals;
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
// Constructors, accessors, mutators
|
||||
|
@ -121,6 +124,62 @@ SubscriptIntegerExpr Substring::last() const {
|
|||
u_);
|
||||
}
|
||||
|
||||
std::optional<std::string> Substring::Fold(FoldingContext &context) {
|
||||
std::optional<SubscriptIntegerExpr::Scalar> lbValue, ubValue;
|
||||
if (first_.has_value()) {
|
||||
lbValue = (*first_)->Fold(context);
|
||||
} else {
|
||||
lbValue = first().Fold(context);
|
||||
}
|
||||
if (lbValue.has_value()) {
|
||||
first_ = IndirectSubscriptIntegerExpr{SubscriptIntegerExpr{*lbValue}};
|
||||
}
|
||||
if (last_.has_value()) {
|
||||
ubValue = (*last_)->Fold(context);
|
||||
} else {
|
||||
ubValue = last().Fold(context);
|
||||
}
|
||||
if (ubValue.has_value()) {
|
||||
last_ = IndirectSubscriptIntegerExpr{SubscriptIntegerExpr{*ubValue}};
|
||||
}
|
||||
if (lbValue.has_value() && ubValue.has_value()) {
|
||||
std::int64_t lbi{lbValue->ToInt64()};
|
||||
std::int64_t ubi{ubValue->ToInt64()};
|
||||
if (ubi < lbi) {
|
||||
// These cases are well defined, and they produce zero-length results.
|
||||
u_ = ""s;
|
||||
first_ = SubscriptIntegerExpr{1};
|
||||
last_ = SubscriptIntegerExpr{0};
|
||||
return {""s};
|
||||
}
|
||||
if (lbi <= 0) {
|
||||
context.messages.Say(
|
||||
"lower bound on substring (%jd) is less than one"_en_US,
|
||||
static_cast<std::intmax_t>(lbi));
|
||||
lbi = 1;
|
||||
first_ = SubscriptIntegerExpr{lbi};
|
||||
}
|
||||
if (ubi <= 0) {
|
||||
u_ = ""s;
|
||||
last_ = SubscriptIntegerExpr{0};
|
||||
return {""s};
|
||||
}
|
||||
if (std::string * str{std::get_if<std::string>(&u_)}) {
|
||||
std::int64_t len = str->size();
|
||||
if (ubi > len) {
|
||||
context.messages.Say(
|
||||
"upper bound on substring (%jd) is greater than character length (%jd)"_en_US);
|
||||
ubi = len;
|
||||
last_ = SubscriptIntegerExpr{ubi};
|
||||
}
|
||||
std::string result{str->substr(lbi - 1, ubi - lbi + 1)};
|
||||
u_ = result;
|
||||
return {result};
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Variable dumping
|
||||
|
||||
template<typename A> std::ostream &Emit(std::ostream &o, const A &x) {
|
||||
|
|
|
@ -164,6 +164,7 @@ private:
|
|||
// variants of sections instead.
|
||||
class Substring {
|
||||
public:
|
||||
using FoldableTrait = std::true_type;
|
||||
CLASS_BOILERPLATE(Substring)
|
||||
Substring(DataRef &&, std::optional<SubscriptIntegerExpr> &&,
|
||||
std::optional<SubscriptIntegerExpr> &&);
|
||||
|
@ -173,6 +174,7 @@ public:
|
|||
SubscriptIntegerExpr first() const;
|
||||
SubscriptIntegerExpr last() const;
|
||||
SubscriptIntegerExpr LEN() const;
|
||||
std::optional<std::string> Fold(FoldingContext &);
|
||||
|
||||
private:
|
||||
std::variant<DataRef, std::string> u_;
|
||||
|
|
|
@ -201,12 +201,12 @@ public:
|
|||
std::optional<resultType> result{parser_.Parse(state)};
|
||||
bool emitMessage{false};
|
||||
if (result.has_value()) {
|
||||
messages.Annex(state.messages());
|
||||
messages.Annex(std::move(state.messages()));
|
||||
if (backtrack.anyTokenMatched()) {
|
||||
state.set_anyTokenMatched();
|
||||
}
|
||||
} else if (state.anyTokenMatched()) {
|
||||
messages.Annex(state.messages());
|
||||
messages.Annex(std::move(state.messages()));
|
||||
backtrack.set_anyTokenMatched();
|
||||
if (state.anyDeferredMessages()) {
|
||||
backtrack.set_anyDeferredMessages(true);
|
||||
|
@ -407,7 +407,7 @@ public:
|
|||
state.messages().Restore(std::move(messages));
|
||||
return ax;
|
||||
}
|
||||
messages.Annex(state.messages());
|
||||
messages.Annex(std::move(state.messages()));
|
||||
bool hadDeferredMessages{state.anyDeferredMessages()};
|
||||
bool anyTokenMatched{state.anyTokenMatched()};
|
||||
state = std::move(backtrack);
|
||||
|
|
|
@ -23,8 +23,8 @@ std::optional<Success> DebugParser::Parse(ParseState &state) const {
|
|||
if (auto ustate{state.userState()}) {
|
||||
if (auto out{ustate->debugOutput()}) {
|
||||
std::string note{str_, length_};
|
||||
Message message{state.GetLocation(),
|
||||
MessageFormattedText{"parser debug: %s"_en_US, note.data()}};
|
||||
Message message{
|
||||
state.GetLocation(), "parser debug: %s"_en_US, note.data()};
|
||||
message.SetContext(state.context().get());
|
||||
message.Emit(*out, ustate->cooked(), true);
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ void Messages::Merge(Messages &&that) {
|
|||
void Messages::Copy(const Messages &that) {
|
||||
for (const Message &m : that.messages_) {
|
||||
Message copy{m};
|
||||
Put(std::move(copy));
|
||||
Say(std::move(copy));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,6 +276,12 @@ void Messages::Emit(
|
|||
}
|
||||
}
|
||||
|
||||
void Messages::AttachTo(Message &msg) {
|
||||
for (const Message &m : messages_) {
|
||||
msg.Attach(m);
|
||||
}
|
||||
}
|
||||
|
||||
bool Messages::AnyFatalError() const {
|
||||
for (const auto &msg : messages_) {
|
||||
if (msg.IsFatal()) {
|
||||
|
|
|
@ -123,7 +123,7 @@ public:
|
|||
Message(ProvenanceRange pr, const MessageFixedText &t)
|
||||
: location_{pr}, text_{t} {}
|
||||
Message(ProvenanceRange pr, const MessageFormattedText &s)
|
||||
: location_{pr}, text_{std::move(s)} {}
|
||||
: location_{pr}, text_{s} {}
|
||||
Message(ProvenanceRange pr, MessageFormattedText &&s)
|
||||
: location_{pr}, text_{std::move(s)} {}
|
||||
Message(ProvenanceRange pr, const MessageExpectedText &t)
|
||||
|
@ -132,12 +132,17 @@ public:
|
|||
Message(CharBlock csr, const MessageFixedText &t)
|
||||
: location_{csr}, text_{t} {}
|
||||
Message(CharBlock csr, const MessageFormattedText &s)
|
||||
: location_{csr}, text_{std::move(s)} {}
|
||||
: location_{csr}, text_{s} {}
|
||||
Message(CharBlock csr, MessageFormattedText &&s)
|
||||
: location_{csr}, text_{std::move(s)} {}
|
||||
Message(CharBlock csr, const MessageExpectedText &t)
|
||||
: location_{csr}, text_{t} {}
|
||||
|
||||
template<typename RANGE, typename A1, typename... As>
|
||||
Message(RANGE r, const MessageFixedText &t, A1 a1, As... as)
|
||||
: location_{r}, text_{
|
||||
MessageFormattedText{t, a1, std::forward<As>(as)...}} {}
|
||||
|
||||
bool attachmentIsContext() const { return attachmentIsContext_; }
|
||||
Reference attachment() const { return attachment_; }
|
||||
|
||||
|
@ -199,17 +204,12 @@ public:
|
|||
|
||||
bool empty() const { return messages_.empty(); }
|
||||
|
||||
Message &Put(Message &&m) {
|
||||
last_ = messages_.emplace_after(last_, std::move(m));
|
||||
return *last_;
|
||||
}
|
||||
|
||||
template<typename... A> Message &Say(A &&... args) {
|
||||
template<typename... A> Message &Say(A... args) {
|
||||
last_ = messages_.emplace_after(last_, std::forward<A>(args)...);
|
||||
return *last_;
|
||||
}
|
||||
|
||||
void Annex(Messages &that) {
|
||||
void Annex(Messages &&that) {
|
||||
if (!that.messages_.empty()) {
|
||||
messages_.splice_after(last_, that.messages_);
|
||||
last_ = that.last_;
|
||||
|
@ -218,7 +218,7 @@ public:
|
|||
}
|
||||
|
||||
void Restore(Messages &&that) {
|
||||
that.Annex(*this);
|
||||
that.Annex(std::move(*this));
|
||||
*this = std::move(that);
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ public:
|
|||
void ResolveProvenances(const CookedSource &);
|
||||
void Emit(std::ostream &, const CookedSource &cooked,
|
||||
bool echoSourceLines = true) const;
|
||||
|
||||
void AttachTo(Message &);
|
||||
bool AnyFatalError() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -143,30 +143,19 @@ public:
|
|||
context_ = context_->attachment();
|
||||
}
|
||||
|
||||
void Say(const MessageFixedText &t) { Say(p_, t); }
|
||||
void Say(MessageFormattedText &&t) { Say(p_, std::move(t)); }
|
||||
void Say(const MessageExpectedText &t) { Say(p_, t); }
|
||||
|
||||
void Say(CharBlock range, const MessageFixedText &t) {
|
||||
template<typename... A> void Say(CharBlock range, A &&... args) {
|
||||
if (deferMessages_) {
|
||||
anyDeferredMessages_ = true;
|
||||
} else {
|
||||
messages_.Say(range, t).SetContext(context_.get());
|
||||
messages_.Say(range, std::forward<A>(args)...).SetContext(context_.get());
|
||||
}
|
||||
}
|
||||
void Say(CharBlock range, MessageFormattedText &&t) {
|
||||
if (deferMessages_) {
|
||||
anyDeferredMessages_ = true;
|
||||
} else {
|
||||
messages_.Say(range, std::move(t)).SetContext(context_.get());
|
||||
}
|
||||
template<typename... A> void Say(const MessageFixedText &text, A &&... args) {
|
||||
Say(p_, text, std::forward<A>(args)...);
|
||||
}
|
||||
void Say(CharBlock range, const MessageExpectedText &t) {
|
||||
if (deferMessages_) {
|
||||
anyDeferredMessages_ = true;
|
||||
} else {
|
||||
messages_.Say(range, t).SetContext(context_.get());
|
||||
}
|
||||
template<typename... A>
|
||||
void Say(const MessageExpectedText &text, A &&... args) {
|
||||
Say(p_, text, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
void Nonstandard(LanguageFeature lf, const MessageFixedText &msg) {
|
||||
|
|
|
@ -43,13 +43,12 @@ void Parsing::Prescan(const std::string &path, Options options) {
|
|||
}
|
||||
if (sourceFile == nullptr) {
|
||||
ProvenanceRange range{allSources.AddCompilerInsertion(path)};
|
||||
MessageFormattedText msg("%s"_err_en_US, fileError.str().data());
|
||||
messages_.Put(Message{range, std::move(msg)});
|
||||
messages_.Say(range, "%s"_err_en_US, fileError.str().data());
|
||||
return;
|
||||
}
|
||||
if (sourceFile->bytes() == 0) {
|
||||
ProvenanceRange range{allSources.AddCompilerInsertion(path)};
|
||||
messages_.Put(Message{range, "file is empty"_err_en_US});
|
||||
messages_.Say(range, "file is empty"_err_en_US);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,7 +111,7 @@ void Parsing::Parse(std::ostream *out) {
|
|||
CHECK(
|
||||
!parseState.anyErrorRecovery() || parseState.messages().AnyFatalError());
|
||||
consumedWholeFile_ = parseState.IsAtEnd();
|
||||
messages_.Annex(parseState.messages());
|
||||
messages_.Annex(std::move(parseState.messages()));
|
||||
finalRestingPlace_ = parseState.GetLocation();
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
return;
|
||||
}
|
||||
if (dir.TokenAt(j).ToString() != "#") {
|
||||
prescanner->Say("missing '#'"_err_en_US, dir.GetTokenProvenanceRange(j));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(j), "missing '#'"_err_en_US);
|
||||
return;
|
||||
}
|
||||
j = dir.SkipBlanks(j + 1);
|
||||
|
@ -383,8 +383,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
// #line is ignored
|
||||
} else if (dirName == "define") {
|
||||
if (nameToken.empty()) {
|
||||
prescanner->Say("#define: missing or invalid name"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(j < tokens ? j : tokens - 1));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(j < tokens ? j : tokens - 1),
|
||||
"#define: missing or invalid name"_err_en_US);
|
||||
return;
|
||||
}
|
||||
nameToken = SaveTokenAsName(nameToken);
|
||||
|
@ -401,17 +401,16 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
isVariadic = true;
|
||||
} else {
|
||||
if (an.empty() || !IsLegalIdentifierStart(an[0])) {
|
||||
prescanner->Say(
|
||||
"#define: missing or invalid argument name"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(j));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(j),
|
||||
"#define: missing or invalid argument name"_err_en_US);
|
||||
return;
|
||||
}
|
||||
argName.push_back(an);
|
||||
}
|
||||
j = dir.SkipBlanks(j + 1);
|
||||
if (j == tokens) {
|
||||
prescanner->Say("#define: malformed argument list"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(tokens - 1));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(tokens - 1),
|
||||
"#define: malformed argument list"_err_en_US);
|
||||
return;
|
||||
}
|
||||
std::string punc{dir.TokenAt(j).ToString()};
|
||||
|
@ -419,21 +418,21 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
break;
|
||||
}
|
||||
if (isVariadic || punc != ",") {
|
||||
prescanner->Say("#define: malformed argument list"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(j));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(j),
|
||||
"#define: malformed argument list"_err_en_US);
|
||||
return;
|
||||
}
|
||||
j = dir.SkipBlanks(j + 1);
|
||||
if (j == tokens) {
|
||||
prescanner->Say("#define: malformed argument list"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(tokens - 1));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(tokens - 1),
|
||||
"#define: malformed argument list"_err_en_US);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (std::set<std::string>(argName.begin(), argName.end()).size() !=
|
||||
argName.size()) {
|
||||
prescanner->Say("#define: argument names are not distinct"_err_en_US,
|
||||
dir.GetTokenProvenance(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenance(dirOffset),
|
||||
"#define: argument names are not distinct"_err_en_US);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -447,13 +446,14 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
}
|
||||
} else if (dirName == "undef") {
|
||||
if (nameToken.empty()) {
|
||||
prescanner->Say("# missing or invalid name"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset));
|
||||
prescanner->Say(
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
|
||||
"# missing or invalid name"_err_en_US);
|
||||
} else {
|
||||
j = dir.SkipBlanks(j + 1);
|
||||
if (j != tokens) {
|
||||
prescanner->Say("#undef: excess tokens at end of directive"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(j, tokens - j));
|
||||
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
|
||||
"#undef: excess tokens at end of directive"_err_en_US);
|
||||
} else {
|
||||
definitions_.erase(nameToken);
|
||||
}
|
||||
|
@ -461,16 +461,14 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
} else if (dirName == "ifdef" || dirName == "ifndef") {
|
||||
if (nameToken.empty()) {
|
||||
prescanner->Say(
|
||||
MessageFormattedText("#%s: missing name"_err_en_US, dirName.data()),
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset));
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
|
||||
"#%s: missing name"_err_en_US, dirName.data());
|
||||
return;
|
||||
}
|
||||
j = dir.SkipBlanks(j + 1);
|
||||
if (j != tokens) {
|
||||
prescanner->Say(MessageFormattedText(
|
||||
"#%s: excess tokens at end of directive"_err_en_US,
|
||||
dirName.data()),
|
||||
dir.GetIntervalProvenanceRange(j, tokens - j));
|
||||
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
|
||||
"#%s: excess tokens at end of directive"_err_en_US, dirName.data());
|
||||
} else if (IsNameDefined(nameToken) == (dirName == "ifdef")) {
|
||||
ifStack_.push(CanDeadElseAppear::Yes);
|
||||
} else {
|
||||
|
@ -486,16 +484,14 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
}
|
||||
} else if (dirName == "else") {
|
||||
if (j != tokens) {
|
||||
prescanner->Say("#else: excess tokens at end of directive"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(j, tokens - j));
|
||||
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
|
||||
"#else: excess tokens at end of directive"_err_en_US);
|
||||
} else if (ifStack_.empty()) {
|
||||
prescanner->Say(
|
||||
"#else: not nested within #if, #ifdef, or #ifndef"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#else: not nested within #if, #ifdef, or #ifndef"_err_en_US);
|
||||
} else if (ifStack_.top() != CanDeadElseAppear::Yes) {
|
||||
prescanner->Say(
|
||||
"#else: already appeared within this #if, #ifdef, or #ifndef"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#else: already appeared within this #if, #ifdef, or #ifndef"_err_en_US);
|
||||
} else {
|
||||
ifStack_.pop();
|
||||
SkipDisabledConditionalCode("else", IsElseActive::No, prescanner,
|
||||
|
@ -503,13 +499,11 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
}
|
||||
} else if (dirName == "elif") {
|
||||
if (ifStack_.empty()) {
|
||||
prescanner->Say(
|
||||
"#elif: not nested within #if, #ifdef, or #ifndef"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#elif: not nested within #if, #ifdef, or #ifndef"_err_en_US);
|
||||
} else if (ifStack_.top() != CanDeadElseAppear::Yes) {
|
||||
prescanner->Say("#elif: #else previously appeared within this "
|
||||
"#if, #ifdef, or #ifndef"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#elif: #else previously appeared within this #if, #ifdef, or #ifndef"_err_en_US);
|
||||
} else {
|
||||
ifStack_.pop();
|
||||
SkipDisabledConditionalCode("elif", IsElseActive::No, prescanner,
|
||||
|
@ -517,33 +511,34 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
}
|
||||
} else if (dirName == "endif") {
|
||||
if (j != tokens) {
|
||||
prescanner->Say("#endif: excess tokens at end of directive"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(j, tokens - j));
|
||||
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
|
||||
"#endif: excess tokens at end of directive"_err_en_US);
|
||||
} else if (ifStack_.empty()) {
|
||||
prescanner->Say("#endif: no #if, #ifdef, or #ifndef"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#endif: no #if, #ifdef, or #ifndef"_err_en_US);
|
||||
} else {
|
||||
ifStack_.pop();
|
||||
}
|
||||
} else if (dirName == "error") {
|
||||
prescanner->Say(
|
||||
MessageFormattedText("#error: %s"_err_en_US, dir.ToString().data()),
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset));
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
|
||||
"#error: %s"_err_en_US, dir.ToString().data());
|
||||
} else if (dirName == "warning") {
|
||||
prescanner->Say(
|
||||
MessageFormattedText("#warning: %s"_en_US, dir.ToString().data()),
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset));
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
|
||||
"#warning: %s"_en_US, dir.ToString().data());
|
||||
} else if (dirName == "include") {
|
||||
if (j == tokens) {
|
||||
prescanner->Say("#include: missing name of file to include"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset));
|
||||
prescanner->Say(
|
||||
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
|
||||
"#include: missing name of file to include"_err_en_US);
|
||||
return;
|
||||
}
|
||||
std::string include;
|
||||
if (dir.TokenAt(j).ToString() == "<") {
|
||||
if (dir.TokenAt(tokens - 1).ToString() != ">") {
|
||||
prescanner->Say("#include: expected '>' at end of directive"_err_en_US,
|
||||
dir.GetIntervalProvenanceRange(j, tokens - j));
|
||||
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
|
||||
"#include: expected '>' at end of directive"_err_en_US);
|
||||
return;
|
||||
}
|
||||
TokenSequence braced{dir, j + 1, tokens - j - 2};
|
||||
|
@ -553,31 +548,28 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
|
|||
include.substr(include.size() - 1, 1) == "\"") {
|
||||
include = include.substr(1, include.size() - 2);
|
||||
} else {
|
||||
prescanner->Say("#include: expected name of file to include"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(j < tokens ? j : tokens - 1));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(j < tokens ? j : tokens - 1),
|
||||
"#include: expected name of file to include"_err_en_US);
|
||||
return;
|
||||
}
|
||||
if (include.empty()) {
|
||||
prescanner->Say("#include: empty include file name"_err_en_US,
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#include: empty include file name"_err_en_US);
|
||||
return;
|
||||
}
|
||||
std::stringstream error;
|
||||
const SourceFile *included{allSources_.Open(include, &error)};
|
||||
if (included == nullptr) {
|
||||
prescanner->Say(
|
||||
MessageFormattedText("#include: %s"_err_en_US, error.str().data()),
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#include: %s"_err_en_US, error.str().data());
|
||||
} else if (included->bytes() > 0) {
|
||||
ProvenanceRange fileRange{
|
||||
allSources_.AddIncludedFile(*included, dir.GetProvenanceRange())};
|
||||
Prescanner{*prescanner}.Prescan(fileRange);
|
||||
}
|
||||
} else {
|
||||
prescanner->Say(MessageFormattedText(
|
||||
"#%s: unknown or unimplemented directive"_err_en_US,
|
||||
dirName.data()),
|
||||
dir.GetTokenProvenanceRange(dirOffset));
|
||||
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
|
||||
"#%s: unknown or unimplemented directive"_err_en_US, dirName.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,8 +631,7 @@ void Preprocessor::SkipDisabledConditionalCode(const std::string &dirName,
|
|||
}
|
||||
}
|
||||
prescanner->Say(
|
||||
MessageFormattedText("#%s: missing #endif"_err_en_US, dirName.data()),
|
||||
provenanceRange);
|
||||
provenanceRange, "#%s: missing #endif"_err_en_US, dirName.data());
|
||||
}
|
||||
|
||||
// Precedence level codes used here to accommodate mixed Fortran and C:
|
||||
|
@ -759,8 +750,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token,
|
|||
left = std::stoll(t, &consumed, 0 /*base to be detected*/);
|
||||
if (consumed < t.size()) {
|
||||
*error = Message{token.GetTokenProvenanceRange(opAt),
|
||||
MessageFormattedText(
|
||||
"uninterpretable numeric constant '%s'"_err_en_US, t.data())};
|
||||
"uninterpretable numeric constant '%s'"_err_en_US, t.data()};
|
||||
return 0;
|
||||
}
|
||||
} else if (IsLegalIdentifierStart(t[0])) {
|
||||
|
@ -980,7 +970,7 @@ bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr,
|
|||
expr3.RemoveBlanks();
|
||||
}
|
||||
if (expr3.empty()) {
|
||||
prescanner->Say("empty expression"_err_en_US, expr.GetProvenanceRange());
|
||||
prescanner->Say(expr.GetProvenanceRange(), "empty expression"_err_en_US);
|
||||
return false;
|
||||
}
|
||||
std::size_t atToken{0};
|
||||
|
@ -989,11 +979,10 @@ bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr,
|
|||
if (error.has_value()) {
|
||||
prescanner->Say(std::move(*error));
|
||||
} else if (atToken < expr3.SizeInTokens()) {
|
||||
prescanner->Say(atToken == 0
|
||||
? "could not parse any expression"_err_en_US
|
||||
: "excess characters after expression"_err_en_US,
|
||||
expr3.GetIntervalProvenanceRange(
|
||||
atToken, expr3.SizeInTokens() - atToken));
|
||||
prescanner->Say(expr3.GetIntervalProvenanceRange(
|
||||
atToken, expr3.SizeInTokens() - atToken),
|
||||
atToken == 0 ? "could not parse any expression"_err_en_US
|
||||
: "excess characters after expression"_err_en_US);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -71,8 +71,8 @@ void Prescanner::Prescan(ProvenanceRange range) {
|
|||
lineStart_ = start_;
|
||||
const bool beganInFixedForm{inFixedForm_};
|
||||
if (prescannerNesting_ > maxPrescannerNesting) {
|
||||
Say("too many nested INCLUDE/#include files, possibly circular"_err_en_US,
|
||||
GetProvenance(start_));
|
||||
Say(GetProvenance(start_),
|
||||
"too many nested INCLUDE/#include files, possibly circular"_err_en_US);
|
||||
return;
|
||||
}
|
||||
while (lineStart_ < limit_) {
|
||||
|
@ -168,8 +168,8 @@ void Prescanner::Statement() {
|
|||
break;
|
||||
case LineClassification::Kind::ConditionalCompilationDirective:
|
||||
case LineClassification::Kind::PreprocessorDirective:
|
||||
Say("preprocessed line resembles a preprocessor directive"_en_US,
|
||||
preprocessed->GetProvenanceRange());
|
||||
Say(preprocessed->GetProvenanceRange(),
|
||||
"preprocessed line resembles a preprocessor directive"_en_US);
|
||||
preprocessed->ToLowerCase().Emit(cooked_);
|
||||
break;
|
||||
case LineClassification::Kind::CompilerDirective:
|
||||
|
@ -218,22 +218,6 @@ TokenSequence Prescanner::TokenizePreprocessorDirective() {
|
|||
return tokens;
|
||||
}
|
||||
|
||||
void Prescanner::Say(Message &&message) {
|
||||
std::optional<ProvenanceRange> range{message.GetProvenanceRange(cooked_)};
|
||||
CHECK(!range.has_value() || cooked_.IsValid(*range));
|
||||
messages_.Put(std::move(message));
|
||||
}
|
||||
|
||||
void Prescanner::Say(MessageFixedText text, ProvenanceRange r) {
|
||||
CHECK(cooked_.IsValid(r));
|
||||
messages_.Put({r, text});
|
||||
}
|
||||
|
||||
void Prescanner::Say(MessageFormattedText &&text, ProvenanceRange r) {
|
||||
CHECK(cooked_.IsValid(r));
|
||||
messages_.Put({r, std::move(text)});
|
||||
}
|
||||
|
||||
void Prescanner::NextLine() {
|
||||
void *vstart{static_cast<void *>(const_cast<char *>(lineStart_))};
|
||||
void *v{std::memchr(vstart, '\n', limit_ - lineStart_)};
|
||||
|
@ -480,8 +464,8 @@ void Prescanner::QuotedCharacterLiteral(TokenSequence &tokens) {
|
|||
}
|
||||
if (*at_ == '\n') {
|
||||
if (!inPreprocessorDirective_) {
|
||||
Say("incomplete character literal"_err_en_US,
|
||||
GetProvenanceRange(start, end));
|
||||
Say(GetProvenanceRange(start, end),
|
||||
"incomplete character literal"_err_en_US);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -514,8 +498,8 @@ void Prescanner::Hollerith(
|
|||
while (count-- > 0) {
|
||||
if (PadOutCharacterLiteral(tokens)) {
|
||||
} else if (*at_ == '\n') {
|
||||
Say("possible truncated Hollerith literal"_en_US,
|
||||
GetProvenanceRange(start, at_));
|
||||
Say(GetProvenanceRange(start, at_),
|
||||
"possible truncated Hollerith literal"_en_US);
|
||||
break;
|
||||
} else {
|
||||
NextChar();
|
||||
|
@ -629,8 +613,8 @@ void Prescanner::FortranInclude(const char *firstQuote) {
|
|||
path += *p;
|
||||
}
|
||||
if (*p != quote) {
|
||||
Say("malformed path name string"_err_en_US,
|
||||
GetProvenanceRange(firstQuote, p));
|
||||
Say(GetProvenanceRange(firstQuote, p),
|
||||
"malformed path name string"_err_en_US);
|
||||
return;
|
||||
}
|
||||
p = SkipWhiteSpace(p + 1);
|
||||
|
@ -638,8 +622,8 @@ void Prescanner::FortranInclude(const char *firstQuote) {
|
|||
const char *garbage{p};
|
||||
for (; *p != '\n' && *p != '!'; ++p) {
|
||||
}
|
||||
Say("excess characters after path name"_en_US,
|
||||
GetProvenanceRange(garbage, p));
|
||||
Say(GetProvenanceRange(garbage, p),
|
||||
"excess characters after path name"_en_US);
|
||||
}
|
||||
std::stringstream error;
|
||||
Provenance provenance{GetProvenance(lineStart_)};
|
||||
|
@ -653,8 +637,7 @@ void Prescanner::FortranInclude(const char *firstQuote) {
|
|||
allSources.PopSearchPathDirectory();
|
||||
}
|
||||
if (included == nullptr) {
|
||||
Say(MessageFormattedText("INCLUDE: %s"_err_en_US, error.str().data()),
|
||||
provenance);
|
||||
Say(provenance, "INCLUDE: %s"_err_en_US, error.str().data());
|
||||
} else if (included->bytes() > 0) {
|
||||
ProvenanceRange includeLineRange{
|
||||
provenance, static_cast<std::size_t>(p - lineStart_)};
|
||||
|
@ -747,7 +730,7 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
|
|||
// Extension: '&' as continuation marker
|
||||
if (features_.ShouldWarn(
|
||||
LanguageFeature::FixedFormContinuationWithColumn1Ampersand)) {
|
||||
Say("nonstandard usage"_en_US, GetProvenance(lineStart_));
|
||||
Say(GetProvenance(lineStart_), "nonstandard usage"_en_US);
|
||||
}
|
||||
return lineStart_ + 1;
|
||||
}
|
||||
|
|
|
@ -70,9 +70,12 @@ public:
|
|||
TokenSequence TokenizePreprocessorDirective();
|
||||
Provenance GetCurrentProvenance() const { return GetProvenance(at_); }
|
||||
|
||||
void Say(Message &&);
|
||||
void Say(MessageFixedText, ProvenanceRange);
|
||||
void Say(MessageFormattedText &&, ProvenanceRange);
|
||||
template<typename... A> Message &Say(A... a) {
|
||||
Message &m{messages_.Say(std::forward<A>(a)...)};
|
||||
std::optional<ProvenanceRange> range{m.GetProvenanceRange(cooked_)};
|
||||
CHECK(!range.has_value() || cooked_.IsValid(*range));
|
||||
return m;
|
||||
}
|
||||
|
||||
private:
|
||||
struct LineClassification {
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
|
||||
#include "expression.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../evaluate/common.h"
|
||||
|
||||
using namespace Fortran::parser::literals;
|
||||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
using Result = ExpressionAnalyzer::Result;
|
||||
using Result = std::optional<evaluate::GenericExpr>;
|
||||
|
||||
// AnalyzeHelper is a local template function that keeps the API
|
||||
// member function ExpressionAnalyzer::Analyze from having to be a
|
||||
|
@ -86,20 +87,45 @@ template<>
|
|||
Result AnalyzeHelper(
|
||||
ExpressionAnalyzer &ea, const parser::CharLiteralConstantSubstring &x) {
|
||||
const auto &range{std::get<parser::SubstringRange>(x.t)};
|
||||
if (!std::get<0>(range.t).has_value() && !std::get<1>(range.t).has_value()) {
|
||||
const std::optional<parser::ScalarIntExpr> &lbTree{std::get<0>(range.t)};
|
||||
const std::optional<parser::ScalarIntExpr> &ubTree{std::get<1>(range.t)};
|
||||
if (!lbTree.has_value() && !ubTree.has_value()) {
|
||||
// "..."(:)
|
||||
return AnalyzeHelper(ea, std::get<parser::CharLiteralConstant>(x.t));
|
||||
}
|
||||
Result lower{AnalyzeHelper(ea, std::get<0>(range.t))};
|
||||
Result upper{AnalyzeHelper(ea, std::get<1>(range.t))};
|
||||
if (lower.has_value() && upper.has_value()) {
|
||||
if (std::optional<evaluate::GenericScalar> lb{lower->ScalarValue()}) {
|
||||
if (std::optional<evaluate::GenericScalar> ub{upper->ScalarValue()}) {
|
||||
// TODO pmk continue here with ToInt64()
|
||||
// TODO: ensure that any kind parameter is 1
|
||||
std::string str{std::get<parser::CharLiteralConstant>(x.t).GetString()};
|
||||
std::optional<evaluate::SubscriptIntegerExpr> lb, ub;
|
||||
if (lbTree.has_value()) {
|
||||
if (Result lbExpr{AnalyzeHelper(ea, *lbTree)}) {
|
||||
if (auto *ie{std::get_if<evaluate::AnyKindIntegerExpr>(&lbExpr->u)}) {
|
||||
lb = evaluate::SubscriptIntegerExpr{std::move(*ie)};
|
||||
} else {
|
||||
ea.context().messages.Say(
|
||||
"scalar integer expression required for substring lower bound"_err_en_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
if (ubTree.has_value()) {
|
||||
if (Result ubExpr{AnalyzeHelper(ea, *ubTree)}) {
|
||||
if (auto *ie{std::get_if<evaluate::AnyKindIntegerExpr>(&ubExpr->u)}) {
|
||||
ub = evaluate::SubscriptIntegerExpr{std::move(*ie)};
|
||||
} else {
|
||||
ea.context().messages.Say(
|
||||
"scalar integer expression required for substring upper bound"_err_en_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!lb.has_value() || !ub.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
evaluate::Substring substring{std::move(str), std::move(lb), std::move(ub)};
|
||||
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
|
||||
evaluate::CharacterExpr<1> chExpr{std::move(ind)};
|
||||
chExpr.Fold(ea.context());
|
||||
evaluate::AnyKindCharacterExpr akcExpr{std::move(chExpr)};
|
||||
evaluate::GenericExpr gExpr{std::move(akcExpr)};
|
||||
return {gExpr};
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -116,9 +142,8 @@ Result AnalyzeHelper(
|
|||
FOR_EACH_INTEGER_KIND(CASE, )
|
||||
#undef CASE
|
||||
default:
|
||||
ea.context().messages.Say(parser::MessageFormattedText{
|
||||
"unimplemented INTEGER kind (%ju)"_err_en_US,
|
||||
static_cast<std::uintmax_t>(kind)});
|
||||
ea.context().messages.Say("unimplemented INTEGER kind (%ju)"_err_en_US,
|
||||
static_cast<std::uintmax_t>(kind));
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace Fortran::semantics {
|
|||
class ExpressionAnalyzer {
|
||||
public:
|
||||
using KindParam = std::int64_t;
|
||||
using Result = std::optional<evaluate::GenericExpr>;
|
||||
|
||||
ExpressionAnalyzer(evaluate::FoldingContext &c, KindParam dIK)
|
||||
: context_{c}, defaultIntegerKind_{dIK} {}
|
||||
|
@ -36,7 +35,7 @@ public:
|
|||
|
||||
// Performs semantic checking on an expression. If successful,
|
||||
// returns its typed expression representation.
|
||||
Result Analyze(const parser::Expr &);
|
||||
std::optional<evaluate::GenericExpr> Analyze(const parser::Expr &);
|
||||
KindParam Analyze(const std::optional<parser::KindParam> &,
|
||||
KindParam defaultKind, KindParam kanjiKind = -1 /* not allowed here */);
|
||||
|
||||
|
|
|
@ -37,12 +37,6 @@ static constexpr auto extension{".mod"};
|
|||
// The initial characters of a file that identify it as a .mod file.
|
||||
static constexpr auto magic{"!mod$ v1 sum:"};
|
||||
|
||||
// Helpers for creating error messages.
|
||||
static parser::Message Error(
|
||||
const SourceName &, parser::MessageFixedText, const std::string &);
|
||||
static parser::Message Error(const SourceName &, parser::MessageFixedText,
|
||||
const std::string &, const std::string &);
|
||||
|
||||
static const SourceName *GetSubmoduleParent(const parser::Program &);
|
||||
static std::string ModFilePath(
|
||||
const std::string &, const SourceName &, const std::string &);
|
||||
|
@ -89,7 +83,7 @@ void ModFileWriter::Write(const Symbol &symbol) {
|
|||
auto path{ModFilePath(dir_, symbol.name(), ancestorName)};
|
||||
PutSymbols(*symbol.scope());
|
||||
if (!WriteFile(path, GetAsString(symbol))) {
|
||||
errors_.emplace_back(
|
||||
errors_.Say(symbol.name(),
|
||||
"Error writing %s: %s"_err_en_US, path.c_str(), std::strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -467,9 +461,8 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
|
|||
auto &parseTree{parsing.parseTree()};
|
||||
if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
|
||||
!parseTree.has_value()) {
|
||||
errors_.push_back(
|
||||
Error(name, "Module file for '%s' is corrupt: %s"_err_en_US,
|
||||
name.ToString(), *path));
|
||||
errors_.Say(name, "Module file for '%s' is corrupt: %s"_err_en_US,
|
||||
name.ToString().data(), path->data());
|
||||
return nullptr;
|
||||
}
|
||||
Scope *parentScope; // the scope this module/submodule goes into
|
||||
|
@ -494,31 +487,28 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
|
|||
|
||||
std::optional<std::string> ModFileReader::FindModFile(
|
||||
const SourceName &name, const std::string &ancestor) {
|
||||
std::vector<parser::Message> errors;
|
||||
parser::Messages attachments;
|
||||
for (auto &dir : directories_) {
|
||||
std::string path{ModFilePath(dir, name, ancestor)};
|
||||
std::ifstream ifstream{path};
|
||||
if (!ifstream.good()) {
|
||||
errors.push_back(
|
||||
Error(name, "%s: %s"_en_US, path, std::string{std::strerror(errno)}));
|
||||
attachments.Say(name, "%s: %s"_en_US, path.data(), std::strerror(errno));
|
||||
} else {
|
||||
std::string line;
|
||||
std::getline(ifstream, line);
|
||||
if (line.compare(0, strlen(magic), magic) == 0) {
|
||||
return path;
|
||||
}
|
||||
errors.push_back(Error(name, "%s: Not a valid module file"_en_US, path));
|
||||
attachments.Say(name, "%s: Not a valid module file"_en_US, path.data());
|
||||
}
|
||||
}
|
||||
auto error{Error(name,
|
||||
auto error{parser::Message{name,
|
||||
ancestor.empty()
|
||||
? "Cannot find module file for '%s'"_err_en_US
|
||||
: "Cannot find module file for submodule '%s' of module '%s'"_err_en_US,
|
||||
name.ToString(), ancestor)};
|
||||
for (auto &e : errors) {
|
||||
error.Attach(e);
|
||||
}
|
||||
errors_.push_back(error);
|
||||
name.ToString().data(), ancestor.data()}};
|
||||
attachments.AttachTo(error);
|
||||
errors_.Say(error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -551,16 +541,4 @@ static std::string ModFilePath(const std::string &dir, const SourceName &name,
|
|||
return path.str();
|
||||
}
|
||||
|
||||
static parser::Message Error(const SourceName &location,
|
||||
parser::MessageFixedText fixedText, const std::string &arg) {
|
||||
return parser::Message{
|
||||
location, parser::MessageFormattedText{fixedText, arg.data()}};
|
||||
}
|
||||
static parser::Message Error(const SourceName &location,
|
||||
parser::MessageFixedText fixedText, const std::string &arg1,
|
||||
const std::string &arg2) {
|
||||
return parser::Message{location,
|
||||
parser::MessageFormattedText{fixedText, arg1.data(), arg2.data()}};
|
||||
}
|
||||
|
||||
} // namespace Fortran::semantics
|
||||
|
|
|
@ -41,9 +41,7 @@ public:
|
|||
void set_directory(const std::string &dir) { dir_ = dir; }
|
||||
|
||||
// Errors encountered during writing. Non-empty if WriteAll returns false.
|
||||
const std::vector<parser::MessageFormattedText> &errors() const {
|
||||
return errors_;
|
||||
}
|
||||
parser::Messages &errors() { return errors_; }
|
||||
|
||||
// Write out all .mod files; if error return false.
|
||||
bool WriteAll();
|
||||
|
@ -59,7 +57,7 @@ private:
|
|||
std::stringstream decls_;
|
||||
std::stringstream contains_;
|
||||
// Any errors encountered during writing:
|
||||
std::vector<parser::MessageFormattedText> errors_;
|
||||
parser::Messages errors_;
|
||||
|
||||
void WriteChildren(const Scope &);
|
||||
void WriteOne(const Scope &);
|
||||
|
@ -86,11 +84,11 @@ public:
|
|||
// Return the Scope for that module/submodule or nullptr on error.
|
||||
Scope *Read(const SourceName &, Scope *ancestor = nullptr);
|
||||
// Errors that occurred when Read returns nullptr.
|
||||
std::vector<parser::Message> &errors() { return errors_; }
|
||||
parser::Messages &errors() { return errors_; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> directories_;
|
||||
std::vector<parser::Message> errors_;
|
||||
parser::Messages errors_;
|
||||
|
||||
std::optional<std::string> FindModFile(
|
||||
const SourceName &, const std::string &);
|
||||
|
|
|
@ -174,7 +174,6 @@ class MessageHandler {
|
|||
public:
|
||||
using Message = parser::Message;
|
||||
using MessageFixedText = parser::MessageFixedText;
|
||||
using MessageFormattedText = parser::MessageFormattedText;
|
||||
|
||||
const parser::Messages &messages() const { return messages_; }
|
||||
|
||||
|
@ -203,6 +202,7 @@ public:
|
|||
// Emit a message and attached message with two names and locations.
|
||||
void Say2(const SourceName &, MessageFixedText &&, const SourceName &,
|
||||
MessageFixedText &&);
|
||||
void Annex(parser::Messages &&);
|
||||
|
||||
private:
|
||||
// Where messages are emitted:
|
||||
|
@ -923,7 +923,7 @@ KindParamValue DeclTypeSpecVisitor::GetKindParamValue(
|
|||
// MessageHandler implementation
|
||||
|
||||
MessageHandler::Message &MessageHandler::Say(Message &&msg) {
|
||||
return messages_.Put(std::move(msg));
|
||||
return messages_.Say(std::move(msg));
|
||||
}
|
||||
MessageHandler::Message &MessageHandler::Say(MessageFixedText &&msg) {
|
||||
CHECK(currStmtSource_);
|
||||
|
@ -939,13 +939,12 @@ MessageHandler::Message &MessageHandler::Say(
|
|||
}
|
||||
MessageHandler::Message &MessageHandler::Say(const SourceName &location,
|
||||
MessageFixedText &&msg, const std::string &arg1) {
|
||||
return Say(Message{location, MessageFormattedText{msg, arg1.c_str()}});
|
||||
return Say(Message{location, msg, arg1.c_str()});
|
||||
}
|
||||
MessageHandler::Message &MessageHandler::Say(const SourceName &location,
|
||||
MessageFixedText &&msg, const SourceName &arg1, const SourceName &arg2) {
|
||||
return Say(Message{location,
|
||||
MessageFormattedText{
|
||||
msg, arg1.ToString().c_str(), arg2.ToString().c_str()}});
|
||||
return Say(
|
||||
Message{location, msg, arg1.ToString().c_str(), arg2.ToString().c_str()});
|
||||
}
|
||||
void MessageHandler::SayAlreadyDeclared(
|
||||
const SourceName &name, const Symbol &prev) {
|
||||
|
@ -954,8 +953,10 @@ void MessageHandler::SayAlreadyDeclared(
|
|||
}
|
||||
void MessageHandler::Say2(const SourceName &name1, MessageFixedText &&msg1,
|
||||
const SourceName &name2, MessageFixedText &&msg2) {
|
||||
Say(name1, std::move(msg1))
|
||||
.Attach(name2, MessageFormattedText{msg2, name2.ToString().data()});
|
||||
Say(name1, std::move(msg1)).Attach(name2, msg2, name2.ToString().data());
|
||||
}
|
||||
void MessageHandler::Annex(parser::Messages &&msgs) {
|
||||
messages_.Annex(std::move(msgs));
|
||||
}
|
||||
|
||||
// ImplicitRulesVisitor implementation
|
||||
|
@ -1383,9 +1384,7 @@ Scope *ModuleVisitor::FindModule(const SourceName &name, Scope *ancestor) {
|
|||
ModFileReader reader{searchDirectories_};
|
||||
auto *scope{reader.Read(name, ancestor)};
|
||||
if (!scope) {
|
||||
for (auto &error : reader.errors()) {
|
||||
Say(std::move(error));
|
||||
}
|
||||
Annex(std::move(reader.errors()));
|
||||
return nullptr;
|
||||
}
|
||||
if (scope->kind() != Scope::Kind::Module) {
|
||||
|
@ -2163,9 +2162,8 @@ bool ResolveNamesVisitor::CheckUseError(
|
|||
for (const auto &pair : details->occurrences()) {
|
||||
const SourceName &location{*pair.first};
|
||||
const SourceName &moduleName{pair.second->name()};
|
||||
msg.Attach(location,
|
||||
MessageFormattedText{"'%s' was use-associated from module '%s'"_en_US,
|
||||
name.ToString().data(), moduleName.ToString().data()});
|
||||
msg.Attach(location, "'%s' was use-associated from module '%s'"_en_US,
|
||||
name.ToString().data(), moduleName.ToString().data());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2244,9 +2242,8 @@ const Symbol *ResolveNamesVisitor::FindComponent(
|
|||
auto &typeName{scope->symbol()->name()};
|
||||
Say(component, "Component '%s' not found in derived type '%s'"_err_en_US,
|
||||
component, typeName)
|
||||
.Attach(typeName,
|
||||
MessageFormattedText{
|
||||
"Declaration of '%s'"_en_US, typeName.ToString().data()});
|
||||
.Attach(
|
||||
typeName, "Declaration of '%s'"_en_US, typeName.ToString().data());
|
||||
return nullptr;
|
||||
}
|
||||
auto *symbol{it->second};
|
||||
|
|
|
@ -217,11 +217,8 @@ std::string CompileFortran(
|
|||
parseTree, parsing.cooked(), directories);
|
||||
Fortran::semantics::ModFileWriter writer;
|
||||
writer.set_directory(driver.moduleDirectory);
|
||||
if (!writer.WriteAll()) {
|
||||
for (const auto &message : writer.errors()) {
|
||||
std::cerr << message.string() << '\n';
|
||||
}
|
||||
}
|
||||
writer.WriteAll();
|
||||
writer.errors().Emit(std::cerr, parsing.cooked());
|
||||
if (driver.dumpSymbols) {
|
||||
Fortran::semantics::DumpSymbols(std::cout);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue