[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:
Tim Keith 2020-01-14 17:31:25 -08:00
parent 44e1433855
commit 8ad8bfb2a8
8 changed files with 50 additions and 63 deletions

View file

@ -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(";

View file

@ -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 &&);
};

View file

@ -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());
}
}
}

View file

@ -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()) {

View file

@ -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());
}

View file

@ -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());

View file

@ -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>";
}

View file

@ -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();
}