[flang-commits] [flang] 7e22542 - [flang] Finer control over error recovery with GetExpr()

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Apr 15 14:25:50 PDT 2022


Author: Peter Klausler
Date: 2022-04-15T14:25:41-07:00
New Revision: 7e225423d39ae1982e9380a4a0836888ab6b3bd8

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

LOG: [flang] Finer control over error recovery with GetExpr()

Prior to this patch, the semantics utility GetExpr() will crash
unconditionally if it encounters a typed expression in the parse
tree that has not been set by expression semantics.  This is the
right behavior when called from lowering, by which time it is known
that the program had no fatal user errors, since it signifies a
fatal internal error.  However, prior to lowering, in the statement
semantics checking code, a more nuanced test should be used before
crashing -- specifically, we should not crash in the face of a
missing typed expression when in error recovery mode.

Getting this right requires GetExpr() and its helper class to have
access to the semantics context, so that it can check AnyFatalErrors()
before crashing.  So this patch touches nearly all of its call sites.

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

Added: 
    

Modified: 
    flang/include/flang/Semantics/tools.h
    flang/lib/Semantics/assignment.cpp
    flang/lib/Semantics/check-allocate.cpp
    flang/lib/Semantics/check-arithmeticif.cpp
    flang/lib/Semantics/check-case.cpp
    flang/lib/Semantics/check-coarray.cpp
    flang/lib/Semantics/check-deallocate.cpp
    flang/lib/Semantics/check-do-forall.cpp
    flang/lib/Semantics/check-io.cpp
    flang/lib/Semantics/check-io.h
    flang/lib/Semantics/check-nullify.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-stop.cpp
    flang/lib/Semantics/data-to-inits.cpp
    flang/lib/Semantics/resolve-directives.cpp
    flang/lib/Semantics/tools.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index b84afe581a5a2..1ee21041dcc27 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -255,22 +255,25 @@ bool ExprHasTypeCategory(
 bool ExprTypeKindIsDefault(
     const SomeExpr &expr, const SemanticsContext &context);
 
-struct GetExprHelper {
+class GetExprHelper {
+public:
+  explicit GetExprHelper(SemanticsContext *context) : context_{context} {}
+  GetExprHelper() : crashIfNoExpr_{true} {}
+
   // Specializations for parse tree nodes that have a typedExpr member.
-  static const SomeExpr *Get(const parser::Expr &);
-  static const SomeExpr *Get(const parser::Variable &);
-  static const SomeExpr *Get(const parser::DataStmtConstant &);
-  static const SomeExpr *Get(const parser::AllocateObject &);
-  static const SomeExpr *Get(const parser::PointerObject &);
-
-  template <typename T>
-  static const SomeExpr *Get(const common::Indirection<T> &x) {
+  const SomeExpr *Get(const parser::Expr &);
+  const SomeExpr *Get(const parser::Variable &);
+  const SomeExpr *Get(const parser::DataStmtConstant &);
+  const SomeExpr *Get(const parser::AllocateObject &);
+  const SomeExpr *Get(const parser::PointerObject &);
+
+  template <typename T> const SomeExpr *Get(const common::Indirection<T> &x) {
     return Get(x.value());
   }
-  template <typename T> static const SomeExpr *Get(const std::optional<T> &x) {
+  template <typename T> const SomeExpr *Get(const std::optional<T> &x) {
     return x ? Get(*x) : nullptr;
   }
-  template <typename T> static const SomeExpr *Get(const T &x) {
+  template <typename T> const SomeExpr *Get(const T &x) {
     static_assert(
         !parser::HasTypedExpr<T>::value, "explicit Get overload must be added");
     if constexpr (ConstraintTrait<T>) {
@@ -281,8 +284,25 @@ struct GetExprHelper {
       return nullptr;
     }
   }
+
+private:
+  SemanticsContext *context_{nullptr};
+  const bool crashIfNoExpr_{false};
 };
 
+// If a SemanticsContext is passed, even if null, it is possible for a null
+// pointer to be returned in the event of an expression that had fatal errors.
+// Use these first two forms in semantics checks for best error recovery.
+// If a SemanticsContext is not passed, a missing expression will
+// cause a crash.
+template <typename T>
+const SomeExpr *GetExpr(SemanticsContext *context, const T &x) {
+  return GetExprHelper{context}.Get(x);
+}
+template <typename T>
+const SomeExpr *GetExpr(SemanticsContext &context, const T &x) {
+  return GetExprHelper{&context}.Get(x);
+}
 template <typename T> const SomeExpr *GetExpr(const T &x) {
   return GetExprHelper{}.Get(x);
 }
@@ -292,7 +312,7 @@ const evaluate::Assignment *GetAssignment(
     const parser::PointerAssignmentStmt &);
 
 template <typename T> std::optional<std::int64_t> GetIntValue(const T &x) {
-  if (const auto *expr{GetExpr(x)}) {
+  if (const auto *expr{GetExpr(nullptr, x)}) {
     return evaluate::ToInt64(*expr);
   } else {
     return std::nullopt;

diff  --git a/flang/lib/Semantics/assignment.cpp b/flang/lib/Semantics/assignment.cpp
index 1fae92c61f3cb..650f31b2dacf4 100644
--- a/flang/lib/Semantics/assignment.cpp
+++ b/flang/lib/Semantics/assignment.cpp
@@ -246,7 +246,7 @@ void AssignmentContext::CheckShape(parser::CharBlock at, const SomeExpr *expr) {
 
 template <typename A> void AssignmentContext::PushWhereContext(const A &x) {
   const auto &expr{std::get<parser::LogicalExpr>(x.t)};
-  CheckShape(expr.thing.value().source, GetExpr(expr));
+  CheckShape(expr.thing.value().source, GetExpr(context_, expr));
   ++whereDepth_;
 }
 

diff  --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp
index 8a3a23ad4f8c2..63a1132630bb7 100644
--- a/flang/lib/Semantics/check-allocate.cpp
+++ b/flang/lib/Semantics/check-allocate.cpp
@@ -187,7 +187,7 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions(
   }
 
   if (info.gotSource || info.gotMold) {
-    if (const auto *expr{GetExpr(DEREF(parserSourceExpr))}) {
+    if (const auto *expr{GetExpr(context, DEREF(parserSourceExpr))}) {
       parser::CharBlock at{parserSourceExpr->source};
       info.sourceExprType = expr->GetType();
       if (!info.sourceExprType) {

diff  --git a/flang/lib/Semantics/check-arithmeticif.cpp b/flang/lib/Semantics/check-arithmeticif.cpp
index e8ce6aab60c95..f87a0045fff5b 100644
--- a/flang/lib/Semantics/check-arithmeticif.cpp
+++ b/flang/lib/Semantics/check-arithmeticif.cpp
@@ -25,7 +25,7 @@ void ArithmeticIfStmtChecker::Leave(
   // R853 Check for a scalar-numeric-expr
   // C849 that shall not be of type complex.
   auto &parsedExpr{std::get<parser::Expr>(arithmeticIfStmt.t)};
-  if (const auto *expr{GetExpr(parsedExpr)}) {
+  if (const auto *expr{GetExpr(context_, parsedExpr)}) {
     if (expr->Rank() > 0) {
       context_.Say(parsedExpr.source,
           "ARITHMETIC IF expression must be a scalar expression"_err_en_US);

diff  --git a/flang/lib/Semantics/check-case.cpp b/flang/lib/Semantics/check-case.cpp
index 262a68596ae7d..bd1bb073539d2 100644
--- a/flang/lib/Semantics/check-case.cpp
+++ b/flang/lib/Semantics/check-case.cpp
@@ -240,7 +240,7 @@ void CaseChecker::Enter(const parser::CaseConstruct &construct) {
   const auto &selectCase{selectCaseStmt.statement};
   const auto &selectExpr{
       std::get<parser::Scalar<parser::Expr>>(selectCase.t).thing};
-  const auto *x{GetExpr(selectExpr)};
+  const auto *x{GetExpr(context_, selectExpr)};
   if (!x) {
     return; // expression semantics failed
   }

diff  --git a/flang/lib/Semantics/check-coarray.cpp b/flang/lib/Semantics/check-coarray.cpp
index 4ce286d0bca1c..6dc4640d61860 100644
--- a/flang/lib/Semantics/check-coarray.cpp
+++ b/flang/lib/Semantics/check-coarray.cpp
@@ -64,7 +64,7 @@ class CriticalBodyEnforce {
 
 template <typename T>
 static void CheckTeamType(SemanticsContext &context, const T &x) {
-  if (const auto *expr{GetExpr(x)}) {
+  if (const auto *expr{GetExpr(context, x)}) {
     if (!IsTeamType(evaluate::GetDerivedTypeSpec(expr->GetType()))) {
       context.Say(parser::FindSourceLocation(x), // C1114
           "Team value must be of type TEAM_TYPE from module ISO_FORTRAN_ENV"_err_en_US);

diff  --git a/flang/lib/Semantics/check-deallocate.cpp b/flang/lib/Semantics/check-deallocate.cpp
index 03c2d6ebdddac..bc8d123786cfc 100644
--- a/flang/lib/Semantics/check-deallocate.cpp
+++ b/flang/lib/Semantics/check-deallocate.cpp
@@ -36,7 +36,7 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) {
             [&](const parser::StructureComponent &structureComponent) {
               // Only perform structureComponent checks it was successfully
               // analyzed in expression analysis.
-              if (GetExpr(allocateObject)) {
+              if (GetExpr(context_, allocateObject)) {
                 if (!IsAllocatableOrPointer(
                         *structureComponent.component.symbol)) { // C932
                   context_.Say(structureComponent.component.source,

diff  --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp
index e1cc4266e8024..fada82df46d7b 100644
--- a/flang/lib/Semantics/check-do-forall.cpp
+++ b/flang/lib/Semantics/check-do-forall.cpp
@@ -501,7 +501,7 @@ class DoContext {
 
   // Semantic checks for the limit and step expressions
   void CheckDoExpression(const parser::ScalarExpr &scalarExpression) {
-    if (const SomeExpr * expr{GetExpr(scalarExpression)}) {
+    if (const SomeExpr * expr{GetExpr(context_, scalarExpression)}) {
       if (!ExprHasTypeCategory(*expr, TypeCategory::Integer)) {
         // No warnings or errors for type INTEGER
         const parser::CharBlock &loc{scalarExpression.thing.value().source};
@@ -569,10 +569,10 @@ class DoContext {
     return symbols;
   }
 
-  static UnorderedSymbolSet GatherSymbolsFromExpression(
-      const parser::Expr &expression) {
+  UnorderedSymbolSet GatherSymbolsFromExpression(
+      const parser::Expr &expression) const {
     UnorderedSymbolSet result;
-    if (const auto *expr{GetExpr(expression)}) {
+    if (const auto *expr{GetExpr(context_, expression)}) {
       for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) {
         result.insert(ResolveAssociations(symbol));
       }
@@ -1022,7 +1022,7 @@ void DoForallChecker::Enter(const parser::Expr &parsedExpr) { ++exprDepth_; }
 void DoForallChecker::Leave(const parser::Expr &parsedExpr) {
   CHECK(exprDepth_ > 0);
   if (--exprDepth_ == 0) { // Only check top level expressions
-    if (const SomeExpr * expr{GetExpr(parsedExpr)}) {
+    if (const SomeExpr * expr{GetExpr(context_, parsedExpr)}) {
       ActualArgumentSet argSet{CollectActualArguments(*expr)};
       for (const evaluate::ActualArgumentRef &argRef : argSet) {
         CheckIfArgIsDoVar(*argRef, parsedExpr.source, context_);

diff  --git a/flang/lib/Semantics/check-io.cpp b/flang/lib/Semantics/check-io.cpp
index 2bb6678e6e177..470ede163cfb7 100644
--- a/flang/lib/Semantics/check-io.cpp
+++ b/flang/lib/Semantics/check-io.cpp
@@ -209,7 +209,7 @@ void IoChecker::Enter(const parser::Format &spec) {
           [&](const parser::Label &) { flags_.set(Flag::LabelFmt); },
           [&](const parser::Star &) { flags_.set(Flag::StarFmt); },
           [&](const parser::Expr &format) {
-            const SomeExpr *expr{GetExpr(format)};
+            const SomeExpr *expr{GetExpr(context_, format)};
             if (!expr) {
               return;
             }
@@ -299,7 +299,7 @@ void IoChecker::Enter(const parser::IdExpr &) { SetSpecifier(IoSpecKind::Id); }
 
 void IoChecker::Enter(const parser::IdVariable &spec) {
   SetSpecifier(IoSpecKind::Id);
-  const auto *expr{GetExpr(spec)};
+  const auto *expr{GetExpr(context_, spec)};
   if (!expr || !expr->GetType()) {
     return;
   }
@@ -546,7 +546,7 @@ void IoChecker::Enter(const parser::IoUnit &spec) {
     if (stmt_ == IoStmtKind::Write) {
       CheckForDefinableVariable(*var, "Internal file");
     }
-    if (const auto *expr{GetExpr(*var)}) {
+    if (const auto *expr{GetExpr(context_, *var)}) {
       if (HasVectorSubscript(*expr)) {
         context_.Say(parser::FindSourceLocation(*var), // C1201
             "Internal file must not have a vector subscript"_err_en_US);
@@ -577,7 +577,7 @@ void IoChecker::Enter(const parser::MsgVariable &var) {
 void IoChecker::Enter(const parser::OutputItem &item) {
   flags_.set(Flag::DataList);
   if (const auto *x{std::get_if<parser::Expr>(&item.u)}) {
-    if (const auto *expr{GetExpr(*x)}) {
+    if (const auto *expr{GetExpr(context_, *x)}) {
       if (evaluate::IsBOZLiteral(*expr)) {
         context_.Say(parser::FindSourceLocation(*x), // C7109
             "Output item must not be a BOZ literal constant"_err_en_US);

diff  --git a/flang/lib/Semantics/check-io.h b/flang/lib/Semantics/check-io.h
index 3e40a14415bda..c23652a2a547b 100644
--- a/flang/lib/Semantics/check-io.h
+++ b/flang/lib/Semantics/check-io.h
@@ -87,7 +87,7 @@ class IoChecker : public virtual BaseChecker {
 
   template <typename R, typename T> std::optional<R> GetConstExpr(const T &x) {
     using DefaultCharConstantType = evaluate::Ascii;
-    if (const SomeExpr * expr{GetExpr(x)}) {
+    if (const SomeExpr * expr{GetExpr(context_, x)}) {
       const auto foldExpr{
           evaluate::Fold(context_.foldingContext(), common::Clone(*expr))};
       if constexpr (std::is_same_v<R, std::string>) {

diff  --git a/flang/lib/Semantics/check-nullify.cpp b/flang/lib/Semantics/check-nullify.cpp
index 4c6e78e7f7e3e..9ee45541fd5c5 100644
--- a/flang/lib/Semantics/check-nullify.cpp
+++ b/flang/lib/Semantics/check-nullify.cpp
@@ -40,7 +40,7 @@ void NullifyChecker::Leave(const parser::NullifyStmt &nullifyStmt) {
               }
             },
             [&](const parser::StructureComponent &structureComponent) {
-              if (const auto *checkedExpr{GetExpr(pointerObject)}) {
+              if (const auto *checkedExpr{GetExpr(context_, pointerObject)}) {
                 if (!IsPointer(*structureComponent.component.symbol)) { // C951
                   messages.Say(structureComponent.component.source,
                       "component in NULLIFY statement must have the POINTER attribute"_err_en_US);

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index d06a79b834f3b..926cf35bb7480 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -50,8 +50,8 @@ class OmpWorkshareBlockChecker {
   bool Pre(const parser::AssignmentStmt &assignment) {
     const auto &var{std::get<parser::Variable>(assignment.t)};
     const auto &expr{std::get<parser::Expr>(assignment.t)};
-    const auto *lhs{GetExpr(var)};
-    const auto *rhs{GetExpr(expr)};
+    const auto *lhs{GetExpr(context_, var)};
+    const auto *rhs{GetExpr(context_, expr)};
     if (lhs && rhs) {
       Tristate isDefined{semantics::IsDefinedAssignment(
           lhs->GetType(), lhs->Rank(), rhs->GetType(), rhs->Rank())};
@@ -65,7 +65,7 @@ class OmpWorkshareBlockChecker {
   }
 
   bool Pre(const parser::Expr &expr) {
-    if (const auto *e{GetExpr(expr)}) {
+    if (const auto *e{GetExpr(context_, expr)}) {
       for (const Symbol &symbol : evaluate::CollectSymbols(*e)) {
         const Symbol &root{GetAssociationRoot(symbol)};
         if (IsFunction(root) &&
@@ -1467,7 +1467,7 @@ void OmpStructureChecker::CheckAtomicUpdateAssignmentStmt(
                   if (const auto *name =
                           std::get_if<Fortran::parser::Name>(&dataRef->u)) {
                     const auto &varSymbol = *name->symbol;
-                    if (const auto *e{GetExpr(expr)}) {
+                    if (const auto *e{GetExpr(context_, expr)}) {
                       for (const Symbol &symbol :
                           evaluate::CollectSymbols(*e)) {
                         if (symbol == varSymbol) {

diff  --git a/flang/lib/Semantics/check-stop.cpp b/flang/lib/Semantics/check-stop.cpp
index ce3482a072bb3..43535b07f029e 100644
--- a/flang/lib/Semantics/check-stop.cpp
+++ b/flang/lib/Semantics/check-stop.cpp
@@ -18,7 +18,7 @@ namespace Fortran::semantics {
 
 void StopChecker::Enter(const parser::StopStmt &stmt) {
   const auto &stopCode{std::get<std::optional<parser::StopCode>>(stmt.t)};
-  if (const auto *expr{GetExpr(stopCode)}) {
+  if (const auto *expr{GetExpr(context_, stopCode)}) {
     const parser::CharBlock &source{parser::FindSourceLocation(stopCode)};
     if (ExprHasTypeCategory(*expr, common::TypeCategory::Integer)) {
       // C1171 default kind

diff  --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index 6bdbf5f6549fd..d41de5ad234e4 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -36,13 +36,13 @@ namespace Fortran::semantics {
 // repetition.
 template <typename DSV = parser::DataStmtValue> class ValueListIterator {
 public:
-  explicit ValueListIterator(const std::list<DSV> &list)
-      : end_{list.end()}, at_{list.begin()} {
+  ValueListIterator(SemanticsContext &context, const std::list<DSV> &list)
+      : context_{context}, end_{list.end()}, at_{list.begin()} {
     SetRepetitionCount();
   }
   bool hasFatalError() const { return hasFatalError_; }
   bool IsAtEnd() const { return at_ == end_; }
-  const SomeExpr *operator*() const { return GetExpr(GetConstant()); }
+  const SomeExpr *operator*() const { return GetExpr(context_, GetConstant()); }
   parser::CharBlock LocateSource() const { return GetConstant().source; }
   ValueListIterator &operator++() {
     if (repetitionsRemaining_ > 0) {
@@ -64,6 +64,7 @@ template <typename DSV = parser::DataStmtValue> class ValueListIterator {
     return std::get<parser::DataStmtConstant>(GetValue().t);
   }
 
+  SemanticsContext &context_;
   listIterator end_, at_;
   ConstantSubscript repetitionsRemaining_{0};
   bool hasFatalError_{false};
@@ -93,7 +94,7 @@ class DataInitializationCompiler {
 public:
   DataInitializationCompiler(DataInitializations &inits,
       evaluate::ExpressionAnalyzer &a, const std::list<DSV> &list)
-      : inits_{inits}, exprAnalyzer_{a}, values_{list} {}
+      : inits_{inits}, exprAnalyzer_{a}, values_{a.context(), list} {}
   const DataInitializations &inits() const { return inits_; }
   bool HasSurplusValues() const { return !values_.IsAtEnd(); }
   bool Scan(const parser::DataStmtObject &);
@@ -134,7 +135,7 @@ bool DataInitializationCompiler<DSV>::Scan(
 
 template <typename DSV>
 bool DataInitializationCompiler<DSV>::Scan(const parser::Variable &var) {
-  if (const auto *expr{GetExpr(var)}) {
+  if (const auto *expr{GetExpr(exprAnalyzer_.context(), var)}) {
     exprAnalyzer_.GetFoldingContext().messages().SetLocation(var.GetSource());
     if (InitDesignator(*expr)) {
       return true;
@@ -160,10 +161,13 @@ template <typename DSV>
 bool DataInitializationCompiler<DSV>::Scan(const parser::DataImpliedDo &ido) {
   const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)};
   auto name{bounds.name.thing.thing};
-  const auto *lowerExpr{GetExpr(bounds.lower.thing.thing)};
-  const auto *upperExpr{GetExpr(bounds.upper.thing.thing)};
-  const auto *stepExpr{
-      bounds.step ? GetExpr(bounds.step->thing.thing) : nullptr};
+  const auto *lowerExpr{
+      GetExpr(exprAnalyzer_.context(), bounds.lower.thing.thing)};
+  const auto *upperExpr{
+      GetExpr(exprAnalyzer_.context(), bounds.upper.thing.thing)};
+  const auto *stepExpr{bounds.step
+          ? GetExpr(exprAnalyzer_.context(), bounds.step->thing.thing)
+          : nullptr};
   if (lowerExpr && upperExpr) {
     // Fold the bounds expressions (again) in case any of them depend
     // on outer implied DO loops.

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 068f944962eb6..2af91517a43d7 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -279,6 +279,18 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     return true;
   }
 
+  bool Pre(const parser::StmtFunctionStmt &x) {
+    const auto &parsedExpr{std::get<parser::Scalar<parser::Expr>>(x.t)};
+    if (const auto *expr{GetExpr(context_, parsedExpr)}) {
+      for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) {
+        if (!IsStmtFunctionDummy(symbol)) {
+          stmtFunctionExprSymbols_.insert(symbol.GetUltimate());
+        }
+      }
+    }
+    return true;
+  }
+
   bool Pre(const parser::OpenMPBlockConstruct &);
   void Post(const parser::OpenMPBlockConstruct &);
 

diff  --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index e0cb86ed8160b..a1b4ea9ec0e2c 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -385,8 +385,9 @@ bool ExprTypeKindIsDefault(
 
 // 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) {
+static void CheckMissingAnalysis(
+    bool crash, SemanticsContext *context, const T &x) {
+  if (crash && !(context && context->AnyFatalError())) {
     std::string buf;
     llvm::raw_string_ostream ss{buf};
     ss << "node has not been analyzed:\n";
@@ -395,34 +396,35 @@ static void CheckMissingAnalysis(bool absent, const T &x) {
   }
 }
 
-template <typename T> static const SomeExpr *GetTypedExpr(const T &x) {
-  CheckMissingAnalysis(!x.typedExpr, x);
-  return common::GetPtrFromOptional(x.typedExpr->v);
-}
 const SomeExpr *GetExprHelper::Get(const parser::Expr &x) {
-  return GetTypedExpr(x);
+  CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x);
+  return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr;
 }
 const SomeExpr *GetExprHelper::Get(const parser::Variable &x) {
-  return GetTypedExpr(x);
+  CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x);
+  return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr;
 }
 const SomeExpr *GetExprHelper::Get(const parser::DataStmtConstant &x) {
-  return GetTypedExpr(x);
+  CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x);
+  return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr;
 }
 const SomeExpr *GetExprHelper::Get(const parser::AllocateObject &x) {
-  return GetTypedExpr(x);
+  CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x);
+  return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr;
 }
 const SomeExpr *GetExprHelper::Get(const parser::PointerObject &x) {
-  return GetTypedExpr(x);
+  CheckMissingAnalysis(crashIfNoExpr_ && !x.typedExpr, context_, x);
+  return x.typedExpr ? common::GetPtrFromOptional(x.typedExpr->v) : nullptr;
 }
 
 const evaluate::Assignment *GetAssignment(const parser::AssignmentStmt &x) {
-  CheckMissingAnalysis(!x.typedAssignment, x);
-  return common::GetPtrFromOptional(x.typedAssignment->v);
+  return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v)
+                           : nullptr;
 }
 const evaluate::Assignment *GetAssignment(
     const parser::PointerAssignmentStmt &x) {
-  CheckMissingAnalysis(!x.typedAssignment, x);
-  return common::GetPtrFromOptional(x.typedAssignment->v);
+  return x.typedAssignment ? common::GetPtrFromOptional(x.typedAssignment->v)
+                           : nullptr;
 }
 
 const Symbol *FindInterface(const Symbol &symbol) {
@@ -998,7 +1000,7 @@ parser::CharBlock GetImageControlStmtLocation(
 }
 
 bool HasCoarray(const parser::Expr &expression) {
-  if (const auto *expr{GetExpr(expression)}) {
+  if (const auto *expr{GetExpr(nullptr, expression)}) {
     for (const Symbol &symbol : evaluate::CollectSymbols(*expr)) {
       if (evaluate::IsCoarray(symbol)) {
         return true;


        


More information about the flang-commits mailing list