[flang] Add std::string ExpressionBase::AsFortran()
This is easier to use when including an expression in an error message and also useful when debugging for dumping expressions. Fix up several places that no longer need to use a temporary std::stringstream. Also change some references to `operator<<` in `formatting.cc` and `symbol.cc` that became ambiguous with this change. Original-commit: flang-compiler/f18@25dc49b6e9 Reviewed-on: https://github.com/flang-compiler/f18/pull/944 Tree-same-pre-rewrite: false
This commit is contained in:
parent
44e1433855
commit
8ad8bfb2a8
|
@ -155,13 +155,10 @@ bool TypeAndShape::IsCompatibleWith(parser::ContextualMessages &messages,
|
|||
bool isElemental) const {
|
||||
const auto &len{that.LEN()};
|
||||
if (!type_.IsTypeCompatibleWith(that.type_)) {
|
||||
std::stringstream lenstr;
|
||||
if (len) {
|
||||
len->AsFortran(lenstr);
|
||||
}
|
||||
messages.Say(
|
||||
"%1$s type '%2$s' is not compatible with %3$s type '%4$s'"_err_en_US,
|
||||
thatIs, that.type_.AsFortran(lenstr.str()), thisIs, type_.AsFortran());
|
||||
thatIs, that.type_.AsFortran(len ? len->AsFortran() : ""), thisIs,
|
||||
type_.AsFortran());
|
||||
return false;
|
||||
}
|
||||
return isElemental ||
|
||||
|
@ -213,11 +210,7 @@ void TypeAndShape::AcquireLEN() {
|
|||
}
|
||||
|
||||
std::ostream &TypeAndShape::Dump(std::ostream &o) const {
|
||||
std::stringstream LENstr;
|
||||
if (LEN_) {
|
||||
LEN_->AsFortran(LENstr);
|
||||
}
|
||||
o << type_.AsFortran(LENstr.str());
|
||||
o << type_.AsFortran(LEN_ ? LEN_->AsFortran() : "");
|
||||
attrs_.Dump(o, EnumToString);
|
||||
if (!shape_.empty()) {
|
||||
o << " dimension(";
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
|
||||
std::optional<DynamicType> GetType() const;
|
||||
int Rank() const;
|
||||
std::string AsFortran() const;
|
||||
std::ostream &AsFortran(std::ostream &) const;
|
||||
static Derived Rewrite(FoldingContext &, Derived &&);
|
||||
};
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <complex>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
|
@ -185,18 +184,14 @@ std::optional<Expr<T>> Folder<T>::GetNamedConstantValue(const Symbol &symbol0) {
|
|||
}
|
||||
mutableObject->set_init(std::nullopt);
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
unwrapped->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be computed as a constant value"_err_en_US,
|
||||
symbol.name(), ss.str());
|
||||
symbol.name(), unwrapped->AsFortran());
|
||||
}
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
init->AsFortran(ss);
|
||||
context_.messages().Say(symbol.name(),
|
||||
"Initialization expression for PARAMETER '%s' (%s) cannot be converted to its type (%s)"_err_en_US,
|
||||
symbol.name(), ss.str(), dyType->AsFortran());
|
||||
symbol.name(), init->AsFortran(), dyType->AsFortran());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "tools.h"
|
||||
#include "../parser/characters.h"
|
||||
#include "../semantics/symbol.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
|
@ -314,24 +315,24 @@ std::ostream &Operation<D, R, O...>::AsFortran(std::ostream &o) const {
|
|||
Precedence thisPrec{ToPrecedence(derived())};
|
||||
if constexpr (operands == 1) {
|
||||
if (thisPrec != Precedence::Top && lhsPrec < thisPrec) {
|
||||
o << '(' << left() << ')';
|
||||
left().AsFortran(o << '(') << ')';
|
||||
} else {
|
||||
o << left();
|
||||
left().AsFortran(o);
|
||||
}
|
||||
} else {
|
||||
if (thisPrec != Precedence::Top &&
|
||||
(lhsPrec < thisPrec ||
|
||||
(lhsPrec == Precedence::Power && thisPrec == Precedence::Power))) {
|
||||
o << '(' << left() << ')';
|
||||
left().AsFortran(o << '(') << ')';
|
||||
} else {
|
||||
o << left();
|
||||
left().AsFortran(o);
|
||||
}
|
||||
o << spelling.infix;
|
||||
Precedence rhsPrec{ToPrecedence(right())};
|
||||
if (thisPrec != Precedence::Top && rhsPrec < thisPrec) {
|
||||
o << '(' << right() << ')';
|
||||
right().AsFortran(o << '(') << ')';
|
||||
} else {
|
||||
o << right();
|
||||
right().AsFortran(o);
|
||||
}
|
||||
}
|
||||
return o << spelling.suffix;
|
||||
|
@ -403,9 +404,7 @@ std::ostream &ArrayConstructor<T>::AsFortran(std::ostream &o) const {
|
|||
template<int KIND>
|
||||
std::ostream &ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
|
||||
std::ostream &o) const {
|
||||
std::stringstream len;
|
||||
LEN().AsFortran(len);
|
||||
o << '[' << GetType().AsFortran(len.str()) << "::";
|
||||
o << '[' << GetType().AsFortran(LEN().AsFortran()) << "::";
|
||||
EmitArray(o, *this);
|
||||
return o << ']';
|
||||
}
|
||||
|
@ -416,6 +415,13 @@ std::ostream &ArrayConstructor<SomeDerived>::AsFortran(std::ostream &o) const {
|
|||
return o << ']';
|
||||
}
|
||||
|
||||
template<typename RESULT>
|
||||
std::string ExpressionBase<RESULT>::AsFortran() const {
|
||||
std::ostringstream ss;
|
||||
AsFortran(ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<typename RESULT>
|
||||
std::ostream &ExpressionBase<RESULT>::AsFortran(std::ostream &o) const {
|
||||
std::visit(
|
||||
|
@ -459,9 +465,7 @@ std::string DynamicType::AsFortran() const {
|
|||
} else if (charLength_->isDeferred()) {
|
||||
result += ':';
|
||||
} else if (const auto &length{charLength_->GetExplicit()}) {
|
||||
std::stringstream ss;
|
||||
length->AsFortran(ss);
|
||||
result += ss.str();
|
||||
result += length->AsFortran();
|
||||
}
|
||||
return result + ')';
|
||||
} else if (IsUnlimitedPolymorphic()) {
|
||||
|
|
|
@ -160,13 +160,10 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
|
|||
"dummy argument", "actual argument");
|
||||
}
|
||||
} else {
|
||||
std::stringstream lenStr;
|
||||
if (const auto &len{actualType.LEN()}) {
|
||||
len->AsFortran(lenStr);
|
||||
}
|
||||
const auto &len{actualType.LEN()};
|
||||
messages.Say(
|
||||
"Actual argument type '%s' is not compatible with dummy argument type '%s'"_err_en_US,
|
||||
actualType.type().AsFortran(lenStr.str()),
|
||||
actualType.type().AsFortran(len ? len->AsFortran() : ""),
|
||||
dummy.type.type().AsFortran());
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "semantics.h"
|
||||
#include "tools.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../evaluate/expression.h"
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
|
@ -22,6 +23,13 @@ static void DumpOptional(std::ostream &os, const char *label, const T &x) {
|
|||
os << ' ' << label << ':' << *x;
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
static void DumpExpr(std::ostream &os, const char *label,
|
||||
const std::optional<evaluate::Expr<T>> &x) {
|
||||
if (x) {
|
||||
x->AsFortran(os << ' ' << label << ':');
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpBool(std::ostream &os, const char *label, bool x) {
|
||||
if (x) {
|
||||
|
@ -84,7 +92,7 @@ void ModuleDetails::set_scope(const Scope *scope) {
|
|||
|
||||
std::ostream &operator<<(std::ostream &os, const SubprogramDetails &x) {
|
||||
DumpBool(os, "isInterface", x.isInterface_);
|
||||
DumpOptional(os, "bindName", x.bindName_);
|
||||
DumpExpr(os, "bindName", x.bindName_);
|
||||
if (x.result_) {
|
||||
os << " result:" << x.result_->name();
|
||||
if (!x.result_->attrs().empty()) {
|
||||
|
@ -336,7 +344,7 @@ std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
|
|||
if (x.type()) {
|
||||
os << " type: " << *x.type();
|
||||
}
|
||||
DumpOptional(os, "bindName", x.bindName_);
|
||||
DumpExpr(os, "bindName", x.bindName_);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
@ -344,13 +352,13 @@ std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) {
|
|||
os << *static_cast<const EntityDetails *>(&x);
|
||||
DumpList(os, "shape", x.shape());
|
||||
DumpList(os, "coshape", x.coshape());
|
||||
DumpOptional(os, "init", x.init_);
|
||||
DumpExpr(os, "init", x.init_);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const AssocEntityDetails &x) {
|
||||
os << *static_cast<const EntityDetails *>(&x);
|
||||
DumpOptional(os, "expr", x.expr());
|
||||
DumpExpr(os, "expr", x.expr());
|
||||
return os;
|
||||
}
|
||||
|
||||
|
@ -360,7 +368,7 @@ std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
|
|||
} else {
|
||||
DumpType(os, x.interface_.type());
|
||||
}
|
||||
DumpOptional(os, "bindName", x.bindName());
|
||||
DumpExpr(os, "bindName", x.bindName());
|
||||
DumpOptional(os, "passName", x.passName());
|
||||
if (x.init()) {
|
||||
if (const Symbol * target{*x.init()}) {
|
||||
|
@ -409,7 +417,7 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|||
os << dummy->name();
|
||||
}
|
||||
os << ')';
|
||||
DumpOptional(os, "bindName", x.bindName());
|
||||
DumpExpr(os, "bindName", x.bindName());
|
||||
if (x.isFunction()) {
|
||||
os << " result(";
|
||||
DumpType(os, x.result());
|
||||
|
@ -455,7 +463,7 @@ std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|||
[&](const TypeParamDetails &x) {
|
||||
DumpOptional(os, "type", x.type());
|
||||
os << ' ' << common::EnumToString(x.attr());
|
||||
DumpOptional(os, "init", x.init());
|
||||
DumpExpr(os, "init", x.init());
|
||||
},
|
||||
[&](const MiscDetails &x) {
|
||||
os << ' ' << MiscDetails::EnumToString(x.kind());
|
||||
|
|
|
@ -122,11 +122,9 @@ void DerivedTypeSpec::EvaluateParameters(
|
|||
continue;
|
||||
}
|
||||
}
|
||||
std::stringstream fortran;
|
||||
expr->AsFortran(fortran);
|
||||
evaluate::SayWithDeclaration(messages, symbol,
|
||||
"Value of type parameter '%s' (%s) is not convertible to its type"_err_en_US,
|
||||
name, fortran.str());
|
||||
name, expr->AsFortran());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,12 +241,10 @@ void DerivedTypeSpec::Instantiate(
|
|||
if (expr->Rank() == 0 &&
|
||||
maybeDynamicType->category() == TypeCategory::Integer) {
|
||||
if (!evaluate::ToInt64(*expr)) {
|
||||
std::stringstream fortran;
|
||||
fortran << *expr;
|
||||
if (auto *msg{foldingContext.messages().Say(
|
||||
"Value of kind type parameter '%s' (%s) is not "
|
||||
"a scalar INTEGER constant"_err_en_US,
|
||||
name, fortran.str())}) {
|
||||
name, expr->AsFortran())}) {
|
||||
msg->Attach(name, "declared here"_en_US);
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +318,7 @@ std::ostream &operator<<(std::ostream &o, const Bound &x) {
|
|||
} else if (x.isDeferred()) {
|
||||
o << ':';
|
||||
} else if (x.expr_) {
|
||||
o << x.expr_;
|
||||
x.expr_->AsFortran(o);
|
||||
} else {
|
||||
o << "<no-expr>";
|
||||
}
|
||||
|
|
|
@ -6,37 +6,30 @@
|
|||
#include "../../lib/parser/message.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using namespace Fortran::evaluate;
|
||||
|
||||
template<typename A> std::string AsFortran(const A &x) {
|
||||
std::stringstream ss;
|
||||
ss << x;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int main() {
|
||||
using DefaultIntegerExpr = Expr<Type<TypeCategory::Integer, 4>>;
|
||||
TEST(DefaultIntegerExpr::Result::AsFortran() == "INTEGER(4)");
|
||||
MATCH("666_4", AsFortran(DefaultIntegerExpr{666}));
|
||||
MATCH("-1_4", AsFortran(-DefaultIntegerExpr{1}));
|
||||
MATCH("666_4", DefaultIntegerExpr{666}.AsFortran());
|
||||
MATCH("-1_4", (-DefaultIntegerExpr{1}).AsFortran());
|
||||
auto ex1{
|
||||
DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}};
|
||||
MATCH("2_4+3_4*(-4_4)", AsFortran(ex1));
|
||||
MATCH("2_4+3_4*(-4_4)", ex1.AsFortran());
|
||||
Fortran::common::IntrinsicTypeDefaultKinds defaults;
|
||||
auto intrinsics{Fortran::evaluate::IntrinsicProcTable::Configure(defaults)};
|
||||
FoldingContext context{
|
||||
Fortran::parser::ContextualMessages{nullptr}, defaults, intrinsics};
|
||||
ex1 = Fold(context, std::move(ex1));
|
||||
MATCH("-10_4", AsFortran(ex1));
|
||||
MATCH("1_4/2_4", AsFortran(DefaultIntegerExpr{1} / DefaultIntegerExpr{2}));
|
||||
MATCH("-10_4", ex1.AsFortran());
|
||||
MATCH("1_4/2_4", (DefaultIntegerExpr{1} / DefaultIntegerExpr{2}).AsFortran());
|
||||
DefaultIntegerExpr a{1};
|
||||
DefaultIntegerExpr b{2};
|
||||
MATCH("1_4", AsFortran(a));
|
||||
MATCH("1_4", a.AsFortran());
|
||||
a = b;
|
||||
MATCH("2_4", AsFortran(a));
|
||||
MATCH("2_4", AsFortran(b));
|
||||
MATCH("2_4", a.AsFortran());
|
||||
MATCH("2_4", b.AsFortran());
|
||||
return testing::Complete();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue