[flang-commits] [flang] e712a92 - [flang] Fix crash on structure constructor as selector

peter klausler via flang-commits flang-commits at lists.llvm.org
Thu Jun 3 14:48:39 PDT 2021


Author: peter klausler
Date: 2021-06-03T14:48:30-07:00
New Revision: e712a92b8fe706c4a736748af324382850d1515c

URL: https://github.com/llvm/llvm-project/commit/e712a92b8fe706c4a736748af324382850d1515c
DIFF: https://github.com/llvm/llvm-project/commit/e712a92b8fe706c4a736748af324382850d1515c.diff

LOG: [flang] Fix crash on structure constructor as selector

In something like "ASSOCIATE(X=>T(1))", the "T(1)" is parsed
as a Variable because it looks like a function reference or
array reference; if it turns out to be a structure constructor,
which is something we can't know until we're able to attempt
generic interface resolution in semantics, the parse tree needs
to be fixed up by replacing the Variable with an Expr.

The compiler could already do this for putative function references
encapsulated as Exprs, so this patch moves some code around and
adds parser::Selector to the overloads of expression analysis.

Differential Revision: https://reviews.llvm.org/D103572

Added: 
    

Modified: 
    flang/include/flang/Semantics/expression.h
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/resolve-names.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h
index 79c35b2d7b93e..16386cf5c16ff 100644
--- a/flang/include/flang/Semantics/expression.h
+++ b/flang/include/flang/Semantics/expression.h
@@ -154,6 +154,7 @@ class ExpressionAnalyzer {
 
   MaybeExpr Analyze(const parser::Expr &);
   MaybeExpr Analyze(const parser::Variable &);
+  MaybeExpr Analyze(const parser::Selector &);
   MaybeExpr Analyze(const parser::Designator &);
   MaybeExpr Analyze(const parser::DataStmtValue &);
   MaybeExpr Analyze(const parser::AllocateObject &);
@@ -295,30 +296,6 @@ class ExpressionAnalyzer {
   template <typename... As> MaybeExpr Analyze(const std::variant<As...> &u) {
     return std::visit(
         [&](const auto &x) {
-          using Ty = std::decay_t<decltype(x)>;
-          // Function references might turn out to be misparsed structure
-          // constructors; we have to try generic procedure resolution
-          // first to be sure.
-          if constexpr (common::IsTypeInList<parser::StructureConstructor,
-                            As...>) {
-            std::optional<parser::StructureConstructor> ctor;
-            MaybeExpr result;
-            if constexpr (std::is_same_v<Ty,
-                              common::Indirection<parser::FunctionReference>>) {
-              result = Analyze(x.value(), &ctor);
-            } else if constexpr (std::is_same_v<Ty,
-                                     parser::FunctionReference>) {
-              result = Analyze(x, &ctor);
-            } else {
-              return Analyze(x);
-            }
-            if (ctor) {
-              // A misparsed function reference is really a structure
-              // constructor.  Repair the parse tree in situ.
-              const_cast<std::variant<As...> &>(u) = std::move(*ctor);
-            }
-            return result;
-          }
           return Analyze(x);
         },
         u);
@@ -413,7 +390,7 @@ void ConformabilityCheck(
 
 namespace Fortran::semantics {
 
-// Semantic analysis of one expression, variable, or designator.
+// Semantic analysis of one expression, variable, selector, designator, &c.
 template <typename A>
 std::optional<evaluate::Expr<evaluate::SomeType>> AnalyzeExpr(
     SemanticsContext &context, const A &expr) {
@@ -449,6 +426,10 @@ class ExprChecker {
     exprAnalyzer_.Analyze(x);
     return false;
   }
+  bool Pre(const parser::Selector &x) {
+    exprAnalyzer_.Analyze(x);
+    return false;
+  }
   bool Pre(const parser::DataStmtValue &x) {
     exprAnalyzer_.Analyze(x);
     return false;

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 5a1643cc8aa33..373c97ea9e05c 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2758,46 +2758,105 @@ MaybeExpr ExpressionAnalyzer::ExprOrVariable(
   }
   if (AssumedTypeDummy(x)) { // C710
     Say("TYPE(*) dummy argument may only be used as an actual argument"_err_en_US);
-  } else if (MaybeExpr result{Analyze(x.u)}) {
+    ResetExpr(x);
+    return std::nullopt;
+  }
+  MaybeExpr result;
+  if constexpr (common::HasMember<parser::StructureConstructor,
+                    std::decay_t<decltype(x.u)>> &&
+      common::HasMember<common::Indirection<parser::FunctionReference>,
+          std::decay_t<decltype(x.u)>>) {
+    if (const auto *funcRef{
+            std::get_if<common::Indirection<parser::FunctionReference>>(
+                &x.u)}) {
+      // Function references in Exprs might turn out to be misparsed structure
+      // constructors; we have to try generic procedure resolution
+      // first to be sure.
+      std::optional<parser::StructureConstructor> ctor;
+      result = Analyze(funcRef->value(), &ctor);
+      if (result && ctor) {
+        // A misparsed function reference is really a structure
+        // constructor.  Repair the parse tree in situ.
+        const_cast<PARSED &>(x).u = std::move(*ctor);
+      }
+    } else {
+      result = Analyze(x.u);
+    }
+  } else {
+    result = Analyze(x.u);
+  }
+  if (result) {
     SetExpr(x, Fold(std::move(*result)));
     return x.typedExpr->v;
+  } else {
+    ResetExpr(x);
+    if (!context_.AnyFatalError()) {
+      std::string buf;
+      llvm::raw_string_ostream dump{buf};
+      parser::DumpTree(dump, x);
+      Say("Internal error: Expression analysis failed on: %s"_err_en_US,
+          dump.str());
+    }
+    return std::nullopt;
   }
-  ResetExpr(x);
-  if (!context_.AnyFatalError()) {
-    std::string buf;
-    llvm::raw_string_ostream dump{buf};
-    parser::DumpTree(dump, x);
-    Say("Internal error: Expression analysis failed on: %s"_err_en_US,
-        dump.str());
-  }
-  return std::nullopt;
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) {
-  auto restorer{GetContextualMessages().SetLocation(expr.source)};
   return ExprOrVariable(expr, expr.source);
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Variable &variable) {
-  auto restorer{GetContextualMessages().SetLocation(variable.GetSource())};
   return ExprOrVariable(variable, variable.GetSource());
 }
 
+MaybeExpr ExpressionAnalyzer::Analyze(const parser::Selector &selector) {
+  if (const auto *var{std::get_if<parser::Variable>(&selector.u)}) {
+    if (!useSavedTypedExprs_ || !var->typedExpr) {
+      parser::CharBlock source{var->GetSource()};
+      auto restorer{GetContextualMessages().SetLocation(source)};
+      FixMisparsedFunctionReference(context_, var->u);
+      if (const auto *funcRef{
+              std::get_if<common::Indirection<parser::FunctionReference>>(
+                  &var->u)}) {
+        // A Selector that parsed as a Variable might turn out during analysis
+        // to actually be a structure constructor.  In that case, repair the
+        // Variable parse tree node into an Expr
+        std::optional<parser::StructureConstructor> ctor;
+        if (MaybeExpr result{Analyze(funcRef->value(), &ctor)}) {
+          if (ctor) {
+            auto &writable{const_cast<parser::Selector &>(selector)};
+            writable.u = parser::Expr{std::move(*ctor)};
+            auto &expr{std::get<parser::Expr>(writable.u)};
+            expr.source = source;
+            SetExpr(expr, Fold(std::move(*result)));
+            return expr.typedExpr->v;
+          } else {
+            SetExpr(*var, Fold(std::move(*result)));
+            return var->typedExpr->v;
+          }
+        } else {
+          ResetExpr(*var);
+          if (context_.AnyFatalError()) {
+            return std::nullopt;
+          }
+        }
+      }
+    }
+  }
+  // Not a Variable -> FunctionReference; handle normally as Variable or Expr
+  return Analyze(selector.u);
+}
+
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::DataStmtConstant &x) {
-  auto restorer{GetContextualMessages().SetLocation(x.source)};
   return ExprOrVariable(x, x.source);
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::AllocateObject &x) {
-  parser::CharBlock source{parser::FindSourceLocation(x)};
-  auto restorer{GetContextualMessages().SetLocation(source)};
-  return ExprOrVariable(x, source);
+  return ExprOrVariable(x, parser::FindSourceLocation(x));
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::PointerObject &x) {
-  parser::CharBlock source{parser::FindSourceLocation(x)};
-  auto restorer{GetContextualMessages().SetLocation(source)};
-  return ExprOrVariable(x, source);
+  return ExprOrVariable(x, parser::FindSourceLocation(x));
 }
 
 Expr<SubscriptInteger> ExpressionAnalyzer::AnalyzeKindSelector(

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 7b4da25f94d55..4d37dd841d574 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5625,10 +5625,10 @@ ConstructVisitor::Selector ConstructVisitor::ResolveSelector(
     const parser::Selector &x) {
   return std::visit(common::visitors{
                         [&](const parser::Expr &expr) {
-                          return Selector{expr.source, EvaluateExpr(expr)};
+                          return Selector{expr.source, EvaluateExpr(x)};
                         },
                         [&](const parser::Variable &var) {
-                          return Selector{var.GetSource(), EvaluateExpr(var)};
+                          return Selector{var.GetSource(), EvaluateExpr(x)};
                         },
                     },
       x.u);


        


More information about the flang-commits mailing list