[flang] Replace formatting of CharBlock & string

Preserve generated strings until consumed by formatting.

bugfix from premature push

Address review comments

Last fix(?)

Use %s formatting for CharBlocks and strings

Use new formatting and fix usage of std::forward<>()

Use forward_list rather than vector to save strings

Original-commit: flang-compiler/f18@8ea478420f
Reviewed-on: https://github.com/flang-compiler/f18/pull/444
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-05-06 09:33:45 -07:00
parent 7334b71023
commit ec6cf76536
21 changed files with 176 additions and 209 deletions

View File

@ -36,7 +36,7 @@ bool TypeAndShape::IsCompatibleWith(
parser::ContextualMessages &messages, const TypeAndShape &that) const {
if (!type_.IsTypeCompatibleWith(that.type_)) {
messages.Say("Target type '%s' is not compatible with '%s'"_err_en_US,
that.type_.AsFortran().c_str(), type_.AsFortran().c_str());
that.type_.AsFortran(), type_.AsFortran());
return false;
}
return CheckConformance(messages, shape_, that.shape_);

View File

@ -589,8 +589,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
context, std::move(funcRef), *callable);
} else {
context.messages().Say(
"%s(real(kind=%d)) cannot be folded on host"_en_US, name.c_str(),
KIND);
"%s(real(kind=%d)) cannot be folded on host"_en_US, name, KIND);
}
}
if (name == "atan" || name == "atan2" || name == "hypot" || name == "mod") {
@ -604,7 +603,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
} else {
context.messages().Say(
"%s(real(kind=%d), real(kind%d)) cannot be folded on host"_en_US,
name.c_str(), KIND, KIND);
name, KIND, KIND);
}
} else if (name == "bessel_jn" || name == "bessel_yn") {
if (args.size() == 2) { // elemental
@ -624,7 +623,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
} else {
context.messages().Say(
"%s(integer(kind=4), real(kind=%d)) cannot be folded on host"_en_US,
name.c_str(), KIND);
name, KIND);
}
}
} else if (name == "abs") {
@ -661,7 +660,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
ValueWithRealFlags<Scalar<T>> y{x.AINT()};
if (y.flags.test(RealFlag::Overflow)) {
context.messages().Say(
"%s intrinsic folding overflow"_en_US, name.c_str());
"%s intrinsic folding overflow"_en_US, name);
}
return y.value;
}));
@ -714,8 +713,7 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldOperation(FoldingContext &context,
context, std::move(funcRef), *callable);
} else {
context.messages().Say(
"%s(complex(kind=%d)) cannot be folded on host"_en_US, name.c_str(),
KIND);
"%s(complex(kind=%d)) cannot be folded on host"_en_US, name, KIND);
}
} else if (name == "conjg") {
return FoldElementalIntrinsic<T, T>(

View File

@ -908,7 +908,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
return std::nullopt;
} else if (!d.typePattern.categorySet.test(type->category)) {
messages.Say("Actual argument for '%s=' has bad type '%s'"_err_en_US,
d.keyword, type->AsFortran().data());
d.keyword, type->AsFortran());
return std::nullopt; // argument has invalid type category
}
bool argOk{false};
@ -961,7 +961,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
if (!argOk) {
messages.Say(
"actual argument for '%s=' has bad type or kind '%s'"_err_en_US,
d.keyword, type->AsFortran().data());
d.keyword, type->AsFortran());
return std::nullopt;
}
}
@ -1315,7 +1315,7 @@ SpecificCall IntrinsicProcTable::Implementation::HandleNull(
} else if (arguments[0].has_value() && arguments[0]->keyword.has_value() &&
arguments[0]->keyword->ToString() != "mold") {
context.messages().Say("Unknown argument '%s' to NULL()"_err_en_US,
arguments[0]->keyword->ToString().data());
arguments[0]->keyword->ToString());
} else {
if (Expr<SomeType> * mold{arguments[0]->GetExpr()}) {
if (IsAllocatableOrPointer(*mold)) {

View File

@ -23,7 +23,7 @@ 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(), "parser debug: %S"_en_US, note};
Message message{state.GetLocation(), "parser debug: %s"_en_US, note};
message.SetContext(state.context().get());
message.Emit(*out, ustate->cooked(), true);
}

View File

@ -14,6 +14,7 @@
#include "message.h"
#include "char-set.h"
#include "parse-tree.h"
#include "../common/idioms.h"
#include <algorithm>
#include <cstdarg>
@ -33,95 +34,62 @@ std::ostream &operator<<(std::ostream &o, const MessageFixedText &t) {
return o;
}
static bool NeedsSpecialFormatting(const char *p) {
bool result{false};
bool tooLate{false};
while (*p != '\0') {
if (*p++ == '%') {
if (*p == 'S' || *p == 'B') {
CHECK(!tooLate);
result = true;
} else if (*p != '%' && *p != 's' && *p != 'd' &&
!((*p == 'z' || *p == 'j') && (p[1] == 'd' || p[1] == 'u'))) {
tooLate = true;
}
}
}
return result;
}
// Some standard formatting codes (e.g., %d) are handled here
// rather than in vsnprintf() because once we have to call vsnprintf(),
// we're no longer able to process our special codes like %S and %B,
// and it's possible that a format might use a common standard formatting
// code before one of our special codes.
static std::string SpecialFormatting(const char *p, va_list &ap) {
std::string result;
while (*p != '\0') {
if (*p != '%') {
result += *p++;
} else {
++p;
switch (*p++) {
case '%': result += '%'; break;
case 's': result += va_arg(ap, const char *); break;
case 'd': result += std::to_string(va_arg(ap, int)); break;
case 'S': result += va_arg(ap, std::string); break;
case 'B': result += va_arg(ap, CharBlock).ToString(); break;
default:
if (p[-1] == 'z' && (*p == 'u' || *p == 'd')) {
result += std::to_string(va_arg(ap, std::size_t));
++p;
break;
}
if (p[-1] == 'j') {
if (*p == 'd') {
result += std::to_string(va_arg(ap, std::intmax_t));
++p;
break;
}
if (*p == 'u') {
result += std::to_string(va_arg(ap, std::uintmax_t));
++p;
break;
}
}
char buffer[256];
vsnprintf(buffer, sizeof buffer, p - 2, ap);
result += buffer;
return result;
}
}
}
return result;
}
MessageFormattedText::MessageFormattedText(MessageFixedText text, ...)
: isFatal_{text.isFatal()} {
const char *p{text.text().begin()};
void MessageFormattedText::Format(const MessageFixedText *text, ...) {
const char *p{text->text().begin()};
std::string asString;
if (*text.text().end() != '\0') {
if (*text->text().end() != '\0') {
// not NUL-terminated
asString = text.text().NULTerminatedToString();
asString = text->text().NULTerminatedToString();
p = asString.c_str();
}
va_list ap;
va_start(ap, text);
if (NeedsSpecialFormatting(p)) {
string_ = SpecialFormatting(p, ap);
} else {
char buffer[256];
vsnprintf(buffer, sizeof buffer, p, ap);
string_ = buffer;
}
int need{vsnprintf(nullptr, 0, p, ap)};
CHECK(need >= 0);
char *buffer{
static_cast<char *>(std::malloc(static_cast<std::size_t>(need) + 1))};
CHECK(buffer != nullptr);
va_end(ap);
va_start(ap, text);
int need2{vsnprintf(buffer, need + 1, p, ap)};
CHECK(need2 == need);
va_end(ap);
string_ = buffer;
std::free(buffer);
conversions_.clear();
}
const char *MessageFormattedText::Convert(const std::string &s) {
conversions_.emplace_front(s);
return conversions_.front().c_str();
}
const char *MessageFormattedText::Convert(std::string &&s) {
conversions_.emplace_front(std::move(s));
return conversions_.front().c_str();
}
const char *MessageFormattedText::Convert(const CharBlock &x) {
return Convert(x.ToString());
}
const char *MessageFormattedText::Convert(CharBlock &&x) {
return Convert(x.ToString());
}
const char *MessageFormattedText::Convert(const Name &n) {
return Convert(n.source);
}
const char *MessageFormattedText::Convert(Name &&n) {
return Convert(n.source);
}
std::string MessageExpectedText::ToString() const {
return std::visit(
common::visitors{
[](const CharBlock &cb) {
return MessageFormattedText("expected '%B'"_err_en_US, cb)
return MessageFormattedText("expected '%s'"_err_en_US, cb)
.MoveString();
},
[](const SetOfChars &set) {
@ -134,21 +102,21 @@ std::string MessageExpectedText::ToString() const {
std::string s{expect.ToString()};
if (s.size() == 1) {
return MessageFormattedText(
"expected end of line or '%S'"_err_en_US, s)
"expected end of line or '%s'"_err_en_US, s)
.MoveString();
} else {
return MessageFormattedText(
"expected end of line or one of '%S'"_err_en_US, s)
"expected end of line or one of '%s'"_err_en_US, s)
.MoveString();
}
}
}
std::string s{expect.ToString()};
if (s.size() != 1) {
return MessageFormattedText("expected one of '%S'"_err_en_US, s)
return MessageFormattedText("expected one of '%s'"_err_en_US, s)
.MoveString();
} else {
return MessageFormattedText("expected '%S'"_err_en_US, s)
return MessageFormattedText("expected '%s'"_err_en_US, s)
.MoveString();
}
},

View File

@ -35,6 +35,8 @@
namespace Fortran::parser {
struct Name;
// Use "..."_err_en_US and "..."_en_US literals to define the static
// text and fatality of a message.
class MessageFixedText {
@ -67,14 +69,17 @@ constexpr MessageFixedText operator""_err_en_US(
}
// The construction of a MessageFormattedText uses a MessageFixedText
// as a vsnprintf()-like formatting string that is applied to the
// following arguments. Additional formatting codes are accepted in
// messages:
// %B - the corresponding argument is a CharBlock
// %S - the corresponding argument is a std::string
// as a vsnprintf() formatting string that is applied to the
// following arguments. CharBlock and std::string argument values are
// also supported; they are automatically converted into char pointers
// that are suitable for '%s' formatting.
class MessageFormattedText {
public:
MessageFormattedText(MessageFixedText, ...);
template<typename... A>
MessageFormattedText(const MessageFixedText &text, A &&... x)
: isFatal_{text.isFatal()} {
Format(&text, Convert(std::forward<A>(x))...);
}
MessageFormattedText(const MessageFormattedText &) = default;
MessageFormattedText(MessageFormattedText &&) = default;
MessageFormattedText &operator=(const MessageFormattedText &) = default;
@ -84,8 +89,21 @@ public:
std::string MoveString() { return std::move(string_); }
private:
std::string string_;
void Format(const MessageFixedText *text, ...);
template<typename A> A Convert(const A &x) { return x; }
template<typename A> common::IfNoLvalue<A, A> Convert(A &&x) {
return std::move(x);
}
const char *Convert(const std::string &);
const char *Convert(std::string &&);
const char *Convert(const CharBlock &);
const char *Convert(CharBlock &&);
const char *Convert(const Name &);
const char *Convert(Name &&);
bool isFatal_{false};
std::string string_;
std::forward_list<std::string> conversions_; // preserves created strings
};
// Represents a formatted rendition of "expected '%s'"_err_en_US
@ -145,9 +163,10 @@ public:
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, as...}} {}
template<typename RANGE, typename A, typename... As>
Message(RANGE r, const MessageFixedText &t, A &&x, As &&... xs)
: location_{r}, text_{MessageFormattedText{
t, std::forward<A>(x), std::forward<As>(xs)...}} {}
bool attachmentIsContext() const { return attachmentIsContext_; }
Reference attachment() const { return attachment_; }
@ -210,7 +229,7 @@ public:
bool empty() const { return messages_.empty(); }
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_;
}

View File

@ -43,7 +43,7 @@ void Parsing::Prescan(const std::string &path, Options options) {
}
if (sourceFile == nullptr) {
ProvenanceRange range{allSources.AddCompilerInsertion(path)};
messages_.Say(range, "%S"_err_en_US, fileError.str());
messages_.Say(range, "%s"_err_en_US, fileError.str());
return;
}
if (sourceFile->bytes() == 0) {

View File

@ -319,8 +319,7 @@ std::optional<TokenSequence> Preprocessor::MacroReplacement(
}
}
}
if (argStart.size() == 1 && k == argStart[0] &&
def.argumentCount() == 0) {
if (argStart.size() == 1 && k == argStart[0] && def.argumentCount() == 0) {
// Subtle: () is zero arguments, not one empty argument,
// unless one argument was expected.
argStart.clear();
@ -472,12 +471,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
if (nameToken.empty()) {
prescanner->Say(
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"#%S: missing name"_err_en_US, dirName);
"#%s: missing name"_err_en_US, dirName);
} else {
j = dir.SkipBlanks(j + 1);
if (j != tokens) {
prescanner->Say(dir.GetIntervalProvenanceRange(j, tokens - j),
"#%S: excess tokens at end of directive"_en_US, dirName);
"#%s: excess tokens at end of directive"_en_US, dirName);
}
doThen = IsNameDefined(nameToken) == (dirName == "ifdef");
}
@ -534,12 +533,12 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
} else if (dirName == "error") {
prescanner->Say(
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"%S"_err_en_US, dir.ToString());
"%s"_err_en_US, dir.ToString());
} else if (dirName == "warning" || dirName == "comment" ||
dirName == "note") {
prescanner->Say(
dir.GetIntervalProvenanceRange(dirOffset, tokens - dirOffset),
"%S"_en_US, dir.ToString());
"%s"_en_US, dir.ToString());
} else if (dirName == "include") {
if (j == tokens) {
prescanner->Say(
@ -585,7 +584,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
const SourceFile *included{allSources_.Open(include, &error)};
if (included == nullptr) {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#include: %S"_err_en_US, error.str());
"#include: %s"_err_en_US, error.str());
} else if (included->bytes() > 0) {
ProvenanceRange fileRange{
allSources_.AddIncludedFile(*included, dir.GetProvenanceRange())};
@ -593,7 +592,7 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner *prescanner) {
}
} else {
prescanner->Say(dir.GetTokenProvenanceRange(dirOffset),
"#%S: unknown or unimplemented directive"_err_en_US, dirName);
"#%s: unknown or unimplemented directive"_err_en_US, dirName);
}
}
@ -654,7 +653,7 @@ void Preprocessor::SkipDisabledConditionalCode(const std::string &dirName,
}
}
}
prescanner->Say(provenanceRange, "#%S: missing #endif"_err_en_US, dirName);
prescanner->Say(provenanceRange, "#%s: missing #endif"_err_en_US, dirName);
}
// Precedence level codes used here to accommodate mixed Fortran and C:
@ -773,7 +772,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),
"Uninterpretable numeric constant '%S'"_err_en_US, t};
"Uninterpretable numeric constant '%s'"_err_en_US, t};
return 0;
}
} else if (IsLegalIdentifierStart(t[0])) {

View File

@ -729,7 +729,7 @@ void Prescanner::FortranInclude(const char *firstQuote) {
allSources.PopSearchPathDirectory();
}
if (included == nullptr) {
Say(provenance, "INCLUDE: %S"_err_en_US, error.str());
Say(provenance, "INCLUDE: %s"_err_en_US, error.str());
} else if (included->bytes() > 0) {
ProvenanceRange includeLineRange{
provenance, static_cast<std::size_t>(p - lineStart_)};

View File

@ -38,7 +38,7 @@ void CheckPointerAssignment(parser::ContextualMessages &messages,
// Default catch-all when RHS of pointer assignment isn't recognized
messages.Say("Pointer target assigned to '%s' must be a designator or "
"a call to a pointer-valued function"_err_en_US,
symbol.name().ToString().c_str());
symbol.name());
}
void CheckPointerAssignment(parser::ContextualMessages &messages,
@ -99,8 +99,7 @@ void CheckPointerAssignment(parser::ContextualMessages &messages,
"result of reference to procedure"_err_en_US;
}
if (error.has_value()) {
if (auto *msg{messages.Say(
*error, lhs.name().ToString().c_str(), funcName.c_str())}) {
if (auto *msg{messages.Say(*error, lhs.name(), funcName)}) {
msg->Attach(lhs.name(), "Declaration of pointer"_en_US);
if (ultimate != nullptr) {
msg->Attach(ultimate->name(), "Declaration of function"_en_US);
@ -138,8 +137,7 @@ void CheckPointerAssignment(parser::ContextualMessages &messages,
}
}
if (error.has_value()) {
if (auto *msg{messages.Say(*error, lhs.name().ToString().c_str(),
ultimate.name().ToString().c_str())}) {
if (auto *msg{messages.Say(*error, lhs.name(), ultimate.name())}) {
msg->Attach(lhs.name(), "Declaration of pointer being assigned"_en_US)
.Attach(ultimate.name(), "Declaration of pointer target"_en_US);
}
@ -184,8 +182,7 @@ void CheckPointerAssignment(parser::ContextualMessages &messages,
"is a procedure designator"_err_en_US;
}
if (error.has_value()) {
if (auto *msg{messages.Say(*error, lhs.name().ToString().c_str(),
rhsName.ToString().c_str())}) {
if (auto *msg{messages.Say(*error, lhs.name(), rhsName)}) {
msg->Attach(lhs.name(), "Declaration of pointer being assigned"_en_US);
}
}

View File

@ -541,16 +541,14 @@ bool AllocationCheckerHelper::RunCoarrayRelatedChecks(
context
.Say(allocateInfo_.typeSpecLoc.value(),
"Type-Spec in ALLOCATE must not be TEAM_TYPE from ISO_FORTRAN_ENV when an allocatable object is a coarray"_err_en_US)
.Attach(name_.source, "'%s' is a coarray"_en_US,
name_.source.ToString().c_str());
.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);
return false;
} else if (IsDerivedTypeFromModule(derived, "iso_c_binding", "c_ptr") ||
IsDerivedTypeFromModule(derived, "iso_c_binding", "c_funptr")) {
context
.Say(allocateInfo_.typeSpecLoc.value(),
"Type-Spec in ALLOCATE must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray"_err_en_US)
.Attach(name_.source, "'%s' is a coarray"_en_US,
name_.source.ToString().c_str());
.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);
return false;
}
}
@ -562,16 +560,14 @@ bool AllocationCheckerHelper::RunCoarrayRelatedChecks(
context
.Say(allocateInfo_.sourceExprLoc.value(),
"SOURCE or MOLD expression type must not be TEAM_TYPE from ISO_FORTRAN_ENV when an allocatable object is a coarray"_err_en_US)
.Attach(name_.source, "'%s' is a coarray"_en_US,
name_.source.ToString().c_str());
.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);
return false;
} else if (IsDerivedTypeFromModule(derived, "iso_c_binding", "c_ptr") ||
IsDerivedTypeFromModule(derived, "iso_c_binding", "c_funptr")) {
context
.Say(allocateInfo_.sourceExprLoc.value(),
"SOURCE or MOLD expression type must not be C_PTR or C_FUNPTR from ISO_C_BINDING when an allocatable object is a coarray"_err_en_US)
.Attach(name_.source, "'%s' is a coarray"_en_US,
name_.source.ToString().c_str());
.Attach(name_.source, "'%s' is a coarray"_en_US, name_.source);
return false;
}
}

View File

@ -90,8 +90,8 @@ void CoarrayChecker::CheckNamesAreDistinct(
void CoarrayChecker::Say2(const parser::CharBlock &name1,
parser::MessageFixedText &&msg1, const parser::CharBlock &name2,
parser::MessageFixedText &&msg2) {
context_.Say(name1, std::move(msg1), name1.ToString().c_str())
.Attach(name2, std::move(msg2), name2.ToString().c_str());
context_.Say(name1, std::move(msg1), name1)
.Attach(name2, std::move(msg2), name2);
}
}

View File

@ -266,15 +266,14 @@ public:
if (do_depth_ == 0) {
messages_.Say(currentStatementSourcePosition_,
"exit from DO CONCURRENT construct (%s)"_err_en_US,
doConcurrentSourcePosition_.ToString().data());
doConcurrentSourcePosition_);
}
// nesting of named constructs is assumed to have been previously checked
// by the name/label resolution pass
} else if (names_.find(nm.value().source) == names_.end()) {
messages_.Say(currentStatementSourcePosition_,
"exit from DO CONCURRENT construct (%s) to construct with name '%s'"_err_en_US,
doConcurrentSourcePosition_.ToString().data(),
nm.value().source.ToString().data());
doConcurrentSourcePosition_, nm.value().source);
}
}
void checkLabelUse(const parser::Label &labelUsed) {

View File

@ -139,7 +139,7 @@ void IoChecker::Enter(const parser::InputItem &spec) {
// This check may be superseded by C928 or C1002.
context_.Say(name.source,
"'%s' must not be a whole assumed size array"_err_en_US,
name.ToString().c_str()); // C1231
name); // C1231
}
}
}
@ -312,7 +312,7 @@ void IoChecker::Enter(const parser::StatusExpr &spec) {
CHECK(stmt_ == IoStmtKind::Close);
if (s != "DELETE" && s != "KEEP") {
context_.Say(parser::FindSourceLocation(spec),
"invalid STATUS value '%s'"_err_en_US, (*charConst).c_str());
"invalid STATUS value '%s'"_err_en_US, *charConst);
}
}
}
@ -476,7 +476,7 @@ void IoChecker::SetSpecifier(IoSpecKind specKind) {
// C1203, C1207, C1210, C1236, C1239, C1242, C1245
if (specifierSet_.test(specKind)) {
context_.Say("duplicate %s specifier"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind)));
}
specifierSet_.set(specKind);
}
@ -506,8 +506,7 @@ void IoChecker::CheckStringValue(IoSpecKind specKind, const std::string &value,
};
if (!specValues.at(specKind).count(parser::ToUpperCaseLetters(value))) {
context_.Say(source, "invalid %s value '%s'"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str(),
value.c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind)), value);
}
}
@ -520,8 +519,8 @@ void IoChecker::CheckStringValue(IoSpecKind specKind, const std::string &value,
void IoChecker::CheckForRequiredSpecifier(IoSpecKind specKind) const {
if (!specifierSet_.test(specKind)) {
context_.Say("%s statement must have a %s specifier"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(stmt_)).c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str());
parser::ToUpperCaseLetters(common::EnumToString(stmt_)),
parser::ToUpperCaseLetters(common::EnumToString(specKind)));
}
}
@ -529,8 +528,7 @@ void IoChecker::CheckForRequiredSpecifier(
bool condition, const std::string &s) const {
if (!condition) {
context_.Say("%s statement must have a %s specifier"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(stmt_)).c_str(),
s.c_str());
parser::ToUpperCaseLetters(common::EnumToString(stmt_)), s);
}
}
@ -538,8 +536,8 @@ void IoChecker::CheckForRequiredSpecifier(
IoSpecKind specKind1, IoSpecKind specKind2) const {
if (specifierSet_.test(specKind1) && !specifierSet_.test(specKind2)) {
context_.Say("if %s appears, %s must also appear"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind1)).c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind2)).c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind1)),
parser::ToUpperCaseLetters(common::EnumToString(specKind2)));
}
}
@ -547,32 +545,30 @@ void IoChecker::CheckForRequiredSpecifier(
IoSpecKind specKind, bool condition, const std::string &s) const {
if (specifierSet_.test(specKind) && !condition) {
context_.Say("if %s appears, %s must also appear"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str(),
s.c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind)), s);
}
}
void IoChecker::CheckForRequiredSpecifier(
bool condition, const std::string &s, IoSpecKind specKind) const {
if (condition && !specifierSet_.test(specKind)) {
context_.Say("if %s appears, %s must also appear"_err_en_US, s.c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str());
context_.Say("if %s appears, %s must also appear"_err_en_US, s,
parser::ToUpperCaseLetters(common::EnumToString(specKind)));
}
}
void IoChecker::CheckForRequiredSpecifier(bool condition1,
const std::string &s1, bool condition2, const std::string &s2) const {
if (condition1 && !condition2) {
context_.Say(
"if %s appears, %s must also appear"_err_en_US, s1.c_str(), s2.c_str());
context_.Say("if %s appears, %s must also appear"_err_en_US, s1, s2);
}
}
void IoChecker::CheckForProhibitedSpecifier(IoSpecKind specKind) const {
if (specifierSet_.test(specKind)) {
context_.Say("%s statement must not have a %s specifier"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(stmt_)).c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str());
parser::ToUpperCaseLetters(common::EnumToString(stmt_)),
parser::ToUpperCaseLetters(common::EnumToString(specKind)));
}
}
@ -580,8 +576,8 @@ void IoChecker::CheckForProhibitedSpecifier(
IoSpecKind specKind1, IoSpecKind specKind2) const {
if (specifierSet_.test(specKind1) && specifierSet_.test(specKind2)) {
context_.Say("if %s appears, %s must not appear"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind1)).c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind2)).c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind1)),
parser::ToUpperCaseLetters(common::EnumToString(specKind2)));
}
}
@ -589,16 +585,15 @@ void IoChecker::CheckForProhibitedSpecifier(
IoSpecKind specKind, bool condition, const std::string &s) const {
if (specifierSet_.test(specKind) && condition) {
context_.Say("if %s appears, %s must not appear"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str(),
s.c_str());
parser::ToUpperCaseLetters(common::EnumToString(specKind)), s);
}
}
void IoChecker::CheckForProhibitedSpecifier(
bool condition, const std::string &s, IoSpecKind specKind) const {
if (condition && specifierSet_.test(specKind)) {
context_.Say("if %s appears, %s must not appear"_err_en_US, s.c_str(),
parser::ToUpperCaseLetters(common::EnumToString(specKind)).c_str());
context_.Say("if %s appears, %s must not appear"_err_en_US, s,
parser::ToUpperCaseLetters(common::EnumToString(specKind)));
}
}

View File

@ -180,7 +180,7 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
if (declTypeSpec->category() == semantics::DeclTypeSpec::TypeStar) {
Say("TYPE(*) assumed-type dummy argument '%s' may not be "
"used except as an actual argument"_err_en_US,
symbol.name().ToString().c_str());
symbol.name());
}
}
return std::nullopt;
@ -200,7 +200,7 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
}
if (subscripts != symbolRank) {
Say("Reference to rank-%d object '%s' has %d subscripts"_err_en_US,
symbolRank, symbol.name().ToString().c_str(), subscripts);
symbolRank, symbol.name(), subscripts);
} else if (subscripts == 0) {
// nothing to check
} else if (Component * component{std::get_if<Component>(&ref.base())}) {
@ -213,7 +213,7 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
if (subscriptRank > 0) {
Say("Subscripts of component '%s' of rank-%d derived type "
"array have rank %d but must all be scalar"_err_en_US,
symbol.name().ToString().c_str(), baseRank, subscriptRank);
symbol.name(), baseRank, subscriptRank);
}
}
} else if (const auto *details{
@ -223,7 +223,7 @@ MaybeExpr ExpressionAnalyzer::CompleteSubscripts(ArrayRef &&ref) {
if (!last->upper().has_value() && details->IsAssumedSize()) {
Say("Assumed-size array '%s' must have explicit final "
"subscript upper bound value"_err_en_US,
symbol.name().ToString().c_str());
symbol.name());
}
}
}
@ -262,7 +262,7 @@ MaybeExpr ExpressionAnalyzer::TopLevelChecks(DataRef &&dataRef) {
if (baseRank > 0) {
Say("Reference to whole rank-%d component '%%%s' of "
"rank-%d array of derived type is not allowed"_err_en_US,
componentRank, symbol.name().ToString().c_str(), baseRank);
componentRank, symbol.name(), baseRank);
} else {
addSubscripts = true;
}
@ -579,7 +579,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::LogicalLiteralConstant &x) {
// BOZ typeless literals
MaybeExpr ExpressionAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
const char *p{x.v.data()};
const char *p{x.v.c_str()};
std::uint64_t base{16};
switch (*p++) {
case 'b': base = 2; break;
@ -592,11 +592,11 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::BOZLiteralConstant &x) {
++p;
auto value{BOZLiteralConstant::Read(p, base, false /*unsigned*/)};
if (*p != '"') {
Say("invalid digit ('%c') in BOZ literal %s"_err_en_US, *p, x.v.data());
Say("Invalid digit ('%c') in BOZ literal '%s'"_err_en_US, *p, x.v);
return std::nullopt;
}
if (value.overflow) {
Say("BOZ literal %s too large"_err_en_US, x.v.data());
Say("BOZ literal '%s' too large"_err_en_US, x.v);
return std::nullopt;
}
return {AsGenericExpr(std::move(value.value))};
@ -704,7 +704,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Substring &ss) {
std::optional<Expr<SubscriptInteger>> last{
GetSubstringBound(std::get<1>(range.t))};
const Symbol &symbol{checked->GetLastSymbol()};
if (std::optional<DynamicType> dynamicType{DynamicType::From(symbol)}) {
if (std::optional<DynamicType> dynamicType{
DynamicType::From(symbol)}) {
if (dynamicType->category == TypeCategory::Character) {
return WrapperHelper<TypeCategory::Character, Designator,
Substring>(dynamicType->kind,
@ -911,7 +912,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::StructureComponent &sc) {
return Designate(DataRef{std::move(*component)});
} else {
Say(name, "component is not in scope of derived TYPE(%s)"_err_en_US,
dtSpec->typeSymbol().name().ToString().c_str());
dtSpec->typeSymbol().name());
}
} else {
Say(name,
@ -1222,7 +1223,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
if (auto *msg{Say(typeName,
"ABSTRACT derived type '%s' may not be used in a "
"structure constructor"_err_en_US,
typeName.ToString().c_str())}) {
typeName)}) {
msg->Attach(
typeSymbol.name(), "Declaration of ABSTRACT derived type"_en_US);
}
@ -1267,7 +1268,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
if (symbol == nullptr) { // C7101
Say(source,
"Keyword '%s=' does not name a component of derived type '%s'"_err_en_US,
source.ToString().c_str(), typeName.ToString().c_str());
source, typeName);
}
} else {
if (anyKeyword) { // C7100
@ -1295,7 +1296,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
Say(source,
"Component '%s' conflicts with another component earlier in "
"this structure constructor"_err_en_US,
symbol->name().ToString().c_str());
symbol->name());
} else if (symbol->test(Symbol::Flag::ParentComp)) {
// Make earlier components unavailable once a whole parent appears.
for (auto it{components.begin()}; it != componentIter; ++it) {
@ -1329,8 +1330,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
"Externally visible object '%s' must not be "
"associated with pointer component '%s' in a "
"PURE function"_err_en_US,
object->name().ToString().c_str(),
pointer->name().ToString().c_str())}) {
object->name(), pointer->name())}) {
msg->Attach(object->name(), "Object declaration"_en_US)
.Attach(pointer->name(), "Pointer declaration"_en_US);
}
@ -1341,13 +1341,13 @@ MaybeExpr ExpressionAnalyzer::Analyze(
Say(expr.source,
"Type parameter '%s' may not appear as a component "
"of a structure constructor"_err_en_US,
symbol->name().ToString().c_str());
symbol->name());
continue;
} else {
Say(expr.source,
"Component '%s' is neither a procedure pointer "
"nor a data object"_err_en_US,
symbol->name().ToString().c_str());
symbol->name());
continue;
}
if (IsPointer(*symbol)) {
@ -1360,7 +1360,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
if (auto *msg{Say(expr.source,
"Value in structure constructor is incompatible with "
"component '%s'"_err_en_US,
symbol->name().ToString().c_str())}) {
symbol->name())}) {
msg->Attach(symbol->name(), "Component declaration"_en_US);
}
}
@ -1381,7 +1381,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(
if (auto *msg{Say(typeName,
"Structure constructor lacks a value for "
"component '%s'"_err_en_US,
symbol->name().ToString().c_str())}) {
symbol->name())}) {
msg->Attach(symbol->name(), "Absent component"_en_US);
}
}
@ -1413,7 +1413,7 @@ ExpressionAnalyzer::AnalyzeProcedureComponentRef(
} else {
Say(name,
"procedure component is not in scope of derived TYPE(%s)"_err_en_US,
dtSpec->typeSymbol().name().ToString().c_str());
dtSpec->typeSymbol().name());
}
} else {
Say(name,
@ -1963,7 +1963,7 @@ bool ExpressionAnalyzer::CheckIntrinsicKind(
return true;
} else {
Say("%s(KIND=%jd) is not a supported type"_err_en_US,
parser::ToUpperCaseLetters(EnumToString(category)).c_str(), kind);
parser::ToUpperCaseLetters(EnumToString(category)), kind);
return false;
}
}
@ -1979,7 +1979,7 @@ bool ExpressionAnalyzer::CheckIntrinsicSize(
return true;
}
Say("%s*%jd is not a supported type"_err_en_US,
parser::ToUpperCaseLetters(EnumToString(category)).c_str(), size);
parser::ToUpperCaseLetters(EnumToString(category)), size);
return false;
}
@ -2010,21 +2010,21 @@ bool ExpressionAnalyzer::EnforceTypeConstraint(parser::CharBlock at,
if (auto type{result->GetType()}) {
if (type->category != category) {
Say(at, "Must have %s type, but is %s"_err_en_US,
parser::ToUpperCaseLetters(EnumToString(category)).c_str(),
parser::ToUpperCaseLetters(type->AsFortran()).c_str());
parser::ToUpperCaseLetters(EnumToString(category)),
parser::ToUpperCaseLetters(type->AsFortran()));
return false;
} else if (defaultKind) {
int kind{context_.defaultKinds().GetDefaultKind(category)};
if (type->kind != kind) {
Say(at, "Must have default kind(%d) of %s type, but is %s"_err_en_US,
kind, parser::ToUpperCaseLetters(EnumToString(category)).c_str(),
parser::ToUpperCaseLetters(type->AsFortran()).c_str());
kind, parser::ToUpperCaseLetters(EnumToString(category)),
parser::ToUpperCaseLetters(type->AsFortran()));
return false;
}
}
} else {
Say(at, "Must have %s type, but is typeless"_err_en_US,
parser::ToUpperCaseLetters(EnumToString(category)).c_str());
parser::ToUpperCaseLetters(EnumToString(category)));
return false;
}
}

View File

@ -130,7 +130,7 @@ void ModFileWriter::Write(const Symbol &symbol) {
ModFilePath(context_.moduleDirectory(), symbol.name(), ancestorName)};
PutSymbols(*symbol.scope());
if (!WriteFile(path, GetAsString(symbol))) {
context_.Say(symbol.name(), "Error writing %s: %s"_err_en_US, path.c_str(),
context_.Say(symbol.name(), "Error writing %s: %s"_err_en_US, path,
std::strerror(errno));
}
}
@ -682,8 +682,7 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
// to parse. Do it only reading the file once.
if (!VerifyHeader(*path)) {
context_.Say(name,
"Module file for '%s' has invalid checksum: %s"_err_en_US,
name.ToString().data(), path->data());
"Module file for '%s' has invalid checksum: %s"_err_en_US, name, *path);
return nullptr;
}
// TODO: Construct parsing with an AllSources reference to share provenance
@ -695,8 +694,8 @@ Scope *ModFileReader::Read(const SourceName &name, Scope *ancestor) {
auto &parseTree{parsing.parseTree()};
if (!parsing.messages().empty() || !parsing.consumedWholeFile() ||
!parseTree.has_value()) {
context_.Say(name, "Module file for '%s' is corrupt: %s"_err_en_US,
name.ToString().data(), path->data());
context_.Say(
name, "Module file for '%s' is corrupt: %s"_err_en_US, name, *path);
return nullptr;
}
Scope *parentScope; // the scope this module/submodule goes into
@ -727,21 +726,21 @@ std::optional<std::string> ModFileReader::FindModFile(
std::string path{ModFilePath(dir, name, ancestor)};
std::ifstream ifstream{path};
if (!ifstream.good()) {
attachments.Say(name, "%s: %s"_en_US, path.data(), std::strerror(errno));
attachments.Say(name, "%s: %s"_en_US, path, std::strerror(errno));
} else {
std::string line;
std::getline(ifstream, line);
if (line.compare(0, strlen(magic), magic) == 0) {
return path;
}
attachments.Say(name, "%s: Not a valid module file"_en_US, path.data());
attachments.Say(name, "%s: Not a valid module file"_en_US, path);
}
}
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().data(), ancestor.data()}};
name, ancestor}};
attachments.AttachTo(error);
context_.Say(std::move(error));
return std::nullopt;

View File

@ -387,12 +387,12 @@ public:
if (optionalGenericSpec.has_value()) {
if (const auto *otherPointer{
std::get_if<parser::Name>(&optionalGenericSpec->u)}) {
if (namePointer->ToString() != otherPointer->ToString()) {
if (namePointer->source != otherPointer->source) {
errorHandler_
.Say(currentPosition_,
parser::MessageFormattedText{
"INTERFACE generic-name (%s) mismatch"_en_US,
namePointer->ToString().c_str()})
namePointer->source})
.Attach(interfaceStmt.source, "mismatched INTERFACE"_en_US);
}
}

View File

@ -75,8 +75,8 @@ private:
// Check that name has been resolved to a symbol
void RewriteMutator::Post(parser::Name &name) {
if (name.symbol == nullptr && errorOnUnresolvedName_) {
messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_en_US,
name.ToString().c_str());
messages_.Say(
name.source, "Internal: no symbol found for '%s'"_err_en_US, name);
}
}

View File

@ -298,8 +298,7 @@ const DeclTypeSpec &Scope::InstantiateIntrinsicType(
"did not resolve to a supported value"_err_en_US,
static_cast<std::intmax_t>(*value),
parser::ToUpperCaseLetters(
common::EnumToString(intrinsic->category()))
.data());
common::EnumToString(intrinsic->category())));
}
}
switch (spec.category()) {

View File

@ -92,15 +92,13 @@ public:
bool HasError(const parser::Name &);
void SetError(Symbol &, bool = true);
template<typename... A>
common::IfNoLvalue<parser::Message &, A...> Say(
parser::CharBlock at, A &&... args) {
return messages_.Say(at, std::move(args)...);
template<typename... A> parser::Message &Say(A &&... args) {
CHECK(location_);
return messages_.Say(*location_, std::forward<A>(args)...);
}
template<typename... A>
common::IfNoLvalue<parser::Message &, A...> Say(A &&... args) {
CHECK(location_);
return messages_.Say(*location_, std::move(args)...);
parser::Message &Say(parser::CharBlock at, A &&... args) {
return messages_.Say(at, std::forward<A>(args)...);
}
parser::Message &Say(parser::Message &&msg) {
return messages_.Say(std::move(msg));

View File

@ -105,7 +105,7 @@ void DerivedTypeSpec::Instantiate(
if (auto *msg{foldingContext.messages().Say(
"Value of kind type parameter '%s' (%s) is not "
"scalar INTEGER constant"_err_en_US,
name.ToString().data(), fortran.str().data())}) {
name, fortran.str())}) {
msg->Attach(name, "declared here"_en_US);
}
}