[flang] Add `std::string ExpressionBase::AsFortran()`
authorTim Keith <tkeith@nvidia.com>
Wed, 15 Jan 2020 01:31:25 +0000 (17:31 -0800)
committerTim Keith <tkeith@nvidia.com>
Wed, 22 Jan 2020 21:50:02 +0000 (13:50 -0800)
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@25dc49b6e9cf5bce61d6d655ab242609cbd28e13
Reviewed-on: https://github.com/flang-compiler/f18/pull/944
Tree-same-pre-rewrite: false

flang/lib/evaluate/characteristics.cc
flang/lib/evaluate/expression.h
flang/lib/evaluate/fold-implementation.h
flang/lib/evaluate/formatting.cc
flang/lib/semantics/check-call.cc
flang/lib/semantics/symbol.cc
flang/lib/semantics/type.cc
flang/test/evaluate/expression.cc

index de03d7d..83c7946 100644 (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(";
index c5003ca..f10ba21 100644 (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 &&);
 };
index 688dee5..d78c527 100644 (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());
           }
         }
       }
index 73b0878..67320ac 100644 (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 << ']';
 }
@@ -417,6 +416,13 @@ std::ostream &ArrayConstructor<SomeDerived>::AsFortran(std::ostream &o) const {
 }
 
 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(
       common::visitors{
@@ -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()) {
index 1888249..a643c38 100644 (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());
   }
 
index 9646059..4015cf7 100644 (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());
index e680697..3e96186 100644 (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>";
   }
index 3145769..24a6e0f 100644 (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();
 }