[flang] Make GenericAssignmentWrapper more like GenericExprWrapper
authorTim Keith <tkeith@nvidia.com>
Wed, 15 Jan 2020 01:39:29 +0000 (17:39 -0800)
committerTim Keith <tkeith@nvidia.com>
Wed, 22 Jan 2020 21:50:02 +0000 (13:50 -0800)
Have it wrap an optional Assignment so that we can distinguish between
unanalyzed and analyzed with error.

Change analysis of PointerAssignmentStmt to proceed with bounds even
if the DataRef or Expr has an error. Otherwise any bounds expressions
won't be analyzed in that case.

In GetExpr() and GetAssignment() if we get an internal error due to an
unanalyzed expression, dump the parse tree for the expression so we have
some context for the error. They should only be called after the
expression analysis phase. At that point, every expression and assignment
should be analyzed, though some may have resulted in errors(indicated by
returning `nullptr`).

Original-commit: flang-compiler/f18@3b865d7703f53099cd491ed1aa9b80b46fee9f58
Reviewed-on: https://github.com/flang-compiler/f18/pull/944
Tree-same-pre-rewrite: false

flang/lib/evaluate/expression.h
flang/lib/semantics/expression.cc
flang/lib/semantics/tools.cc
flang/lib/semantics/tools.h
flang/tools/f18/f18.cc

index f10ba21..00363b5 100644 (file)
@@ -847,9 +847,10 @@ struct GenericExprWrapper {
 
 // Like GenericExprWrapper but for analyzed assignments
 struct GenericAssignmentWrapper {
+  GenericAssignmentWrapper() {}
   explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {}
   ~GenericAssignmentWrapper();
-  Assignment v;
+  std::optional<Assignment> v;  // vacant if error
 };
 
 FOR_EACH_CATEGORY_TYPE(extern template class Expr, )
index a5eb00b..e24b310 100644 (file)
@@ -1915,7 +1915,9 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
     ArgumentAnalyzer analyzer{*this};
     analyzer.Analyze(std::get<parser::Variable>(x.t));
     analyzer.Analyze(std::get<parser::Expr>(x.t));
-    if (!analyzer.fatalErrors()) {
+    if (analyzer.fatalErrors()) {
+      x.typedAssignment.reset(new GenericAssignmentWrapper{});
+    } else {
       std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
       x.typedAssignment.reset(new GenericAssignmentWrapper{procRef
               ? Assignment{std::move(*procRef)}
@@ -1923,50 +1925,55 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
                     Fold(analyzer.MoveExpr(0)), Fold(analyzer.MoveExpr(1))}}});
     }
   }
-  return x.typedAssignment ? &x.typedAssignment->v : nullptr;
+  return common::GetPtrFromOptional(x.typedAssignment->v);
 }
 
 const Assignment *ExpressionAnalyzer::Analyze(
     const parser::PointerAssignmentStmt &x) {
-  MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
-  MaybeExpr rhs{Analyze(std::get<parser::Expr>(x.t))};
-  if (!lhs || !rhs) {
-    return nullptr;
-  }
-  Assignment::PointerAssignment assignment{
-      Fold(std::move(*lhs)), Fold(std::move(*rhs))};
-  std::visit(
-      common::visitors{
-          [&](const std::list<parser::BoundsRemapping> &list) {
-            if (!list.empty()) {
-              Assignment::PointerAssignment::BoundsRemapping bounds;
-              for (const auto &elem : list) {
-                auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))};
-                auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))};
-                if (lower && upper) {
-                  bounds.emplace_back(
-                      Fold(std::move(*lower)), Fold(std::move(*upper)));
+  if (!x.typedAssignment) {
+    MaybeExpr lhs{Analyze(std::get<parser::DataRef>(x.t))};
+    MaybeExpr rhs{Analyze(std::get<parser::Expr>(x.t))};
+    decltype(Assignment::PointerAssignment::bounds) pointerBounds;
+    std::visit(
+        common::visitors{
+            [&](const std::list<parser::BoundsRemapping> &list) {
+              if (!list.empty()) {
+                Assignment::PointerAssignment::BoundsRemapping bounds;
+                for (const auto &elem : list) {
+                  auto lower{AsSubscript(Analyze(std::get<0>(elem.t)))};
+                  auto upper{AsSubscript(Analyze(std::get<1>(elem.t)))};
+                  if (lower && upper) {
+                    bounds.emplace_back(
+                        Fold(std::move(*lower)), Fold(std::move(*upper)));
+                  }
                 }
+                pointerBounds = bounds;
               }
-              assignment.bounds = bounds;
-            }
-          },
-          [&](const std::list<parser::BoundsSpec> &list) {
-            if (!list.empty()) {
-              Assignment::PointerAssignment::BoundsSpec bounds;
-              for (const auto &bound : list) {
-                if (auto lower{AsSubscript(Analyze(bound.v))}) {
-                  bounds.emplace_back(Fold(std::move(*lower)));
+            },
+            [&](const std::list<parser::BoundsSpec> &list) {
+              if (!list.empty()) {
+                Assignment::PointerAssignment::BoundsSpec bounds;
+                for (const auto &bound : list) {
+                  if (auto lower{AsSubscript(Analyze(bound.v))}) {
+                    bounds.emplace_back(Fold(std::move(*lower)));
+                  }
                 }
+                pointerBounds = bounds;
               }
-              assignment.bounds = bounds;
-            }
-          },
-      },
-      std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
-  x.typedAssignment.reset(
-      new GenericAssignmentWrapper{Assignment{std::move(assignment)}});
-  return &x.typedAssignment->v;
+            },
+        },
+        std::get<parser::PointerAssignmentStmt::Bounds>(x.t).u);
+    if (!lhs || !rhs) {
+      x.typedAssignment.reset(new GenericAssignmentWrapper{});
+    } else {
+      Assignment::PointerAssignment assignment{
+          Fold(std::move(*lhs)), Fold(std::move(*rhs))};
+      assignment.bounds = pointerBounds;
+      x.typedAssignment.reset(
+          new GenericAssignmentWrapper{Assignment{std::move(assignment)}});
+    }
+  }
+  return common::GetPtrFromOptional(x.typedAssignment->v);
 }
 
 static bool IsExternalCalledImplicitly(
index 18c5c82..8342e41 100644 (file)
 #include "type.h"
 #include "../common/Fortran.h"
 #include "../common/indirection.h"
+#include "../parser/dump-parse-tree.h"
 #include "../parser/message.h"
 #include "../parser/parse-tree.h"
 #include "../parser/tools.h"
 #include <algorithm>
 #include <set>
+#include <sstream>
 #include <variant>
 
 namespace Fortran::semantics {
@@ -383,14 +385,33 @@ bool ExprTypeKindIsDefault(
       dynamicType->kind() == context.GetDefaultKind(dynamicType->category());
 }
 
+// If an analyzed expr or assignment is missing, dump the node and die.
+template<typename T> static void CheckMissingAnalysis(bool absent, const T &x) {
+  if (absent) {
+    std::ostringstream ss;
+    ss << "node has not been analyzed:\n";
+    parser::DumpTree(ss, x);
+    common::die(ss.str().c_str());
+  }
+}
+
+const SomeExpr *GetExprHelper::Get(const parser::Expr &x) {
+  CheckMissingAnalysis(!x.typedExpr, x);
+  return common::GetPtrFromOptional(x.typedExpr->v);
+}
+const SomeExpr *GetExprHelper::Get(const parser::Variable &x) {
+  CheckMissingAnalysis(!x.typedExpr, x);
+  return common::GetPtrFromOptional(x.typedExpr->v);
+}
+
 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) {
-  const auto &typed{x.typedAssignment};
-  return typed ? &typed->v : nullptr;
+  CheckMissingAnalysis(!x.typedAssignment, x);
+  return common::GetPtrFromOptional(x.typedAssignment->v);
 }
 const evaluate::Assignment *GetAssignment(
     const parser::PointerAssignmentStmt &x) {
-  const auto &typed{x.typedAssignment};
-  return typed ? &typed->v : nullptr;
+  CheckMissingAnalysis(!x.typedAssignment, x);
+  return common::GetPtrFromOptional(x.typedAssignment->v);
 }
 
 const Symbol *FindInterface(const Symbol &symbol) {
index d857654..83741bd 100644 (file)
@@ -226,12 +226,8 @@ bool ExprTypeKindIsDefault(
     const SomeExpr &expr, const SemanticsContext &context);
 
 struct GetExprHelper {
-  const SomeExpr *Get(const parser::Expr::TypedExpr &x) {
-    CHECK(x);
-    return x && x->v ? &*x->v : nullptr;
-  }
-  const SomeExpr *Get(const parser::Expr &x) { return Get(x.typedExpr); }
-  const SomeExpr *Get(const parser::Variable &x) { return Get(x.typedExpr); }
+  const SomeExpr *Get(const parser::Expr &);
+  const SomeExpr *Get(const parser::Variable &);
   template<typename T> const SomeExpr *Get(const common::Indirection<T> &x) {
     return Get(x.value());
   }
index f23f6e4..6e68540 100644 (file)
@@ -172,7 +172,11 @@ static Fortran::parser::AnalyzedObjectsAsFortran asFortran{
       }
     },
     [](std::ostream &o, const Fortran::evaluate::GenericAssignmentWrapper &x) {
-      x.v.AsFortran(o);
+      if (x.v) {
+        x.v->AsFortran(o);
+      } else {
+        o << "(bad assignment)";
+      }
     },
     [](std::ostream &o, const Fortran::evaluate::ProcedureRef &x) {
       x.AsFortran(o << "CALL ");