[flang-commits] [flang] a567961 - [flang] Better messages for function vs. array errors

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Jan 18 15:42:16 PST 2022


Author: Peter Klausler
Date: 2022-01-18T15:42:08-08:00
New Revision: a56796157498a2642e5bec84f5247a3460f8222d

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

LOG: [flang] Better messages for function vs. array errors

When a scalar-valued function with no distinct RESULT
is being called recursively in its own executable part,
emit a better message about the error.  Clean up the
code that resolves function vs. array ambiguities in
expression semantics.

Update to address review comment

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

Added: 
    

Modified: 
    flang/include/flang/Semantics/tools.h
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/tools.cpp
    flang/test/Semantics/resolve59.f90
    flang/test/Semantics/resolve93.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 6047eeae9dfc4..c52ee29c82c43 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -96,7 +96,8 @@ bool IsPointerDummy(const Symbol &);
 bool IsBindCProcedure(const Symbol &);
 bool IsBindCProcedure(const Scope &);
 bool IsProcName(const Symbol &); // proc-name
-bool IsFunctionResultWithSameNameAsFunction(const Symbol &);
+// Returns a pointer to the function's symbol when true, else null
+const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &);
 bool IsOrContainsEventOrLockComponent(const Symbol &);
 bool CanBeTypeBoundProc(const Symbol *);
 // Does a non-PARAMETER symbol have explicit initialization with =value or

diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index cf4b5485362b4..56d3b82a657e7 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2781,33 +2781,43 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedBinary &x) {
       "No operator %s defined for %s and %s"_err_en_US, nullptr, true);
 }
 
-static void CheckFuncRefToArrayElementRefHasSubscripts(
-    semantics::SemanticsContext &context,
+// Returns true if a parsed function reference should be converted
+// into an array element reference.
+static bool CheckFuncRefToArrayElement(semantics::SemanticsContext &context,
     const parser::FunctionReference &funcRef) {
   // Emit message if the function reference fix will end up an array element
-  // reference with no subscripts because it will not be possible to later tell
-  // the 
diff erence in expressions between empty subscript list due to bad
-  // subscripts error recovery or because the user did not put any.
-  if (std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t).empty()) {
-    auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
-    const auto *name{std::get_if<parser::Name>(&proc.u)};
-    if (!name) {
-      name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component;
-    }
-    auto &msg{context.Say(funcRef.v.source,
-        name->symbol && name->symbol->Rank() == 0
-            ? "'%s' is not a function"_err_en_US
-            : "Reference to array '%s' with empty subscript list"_err_en_US,
-        name->source)};
-    if (name->symbol) {
-      if (semantics::IsFunctionResultWithSameNameAsFunction(*name->symbol)) {
-        msg.Attach(name->source,
-            "A result variable must be declared with RESULT to allow recursive "
-            "function calls"_en_US);
-      } else {
+  // reference with no subscripts, or subscripts on a scalar, because it will
+  // not be possible to later distinguish in expressions between an empty
+  // subscript list due to bad subscripts error recovery or because the
+  // user did not put any.
+  auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)};
+  const auto *name{std::get_if<parser::Name>(&proc.u)};
+  if (!name) {
+    name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component;
+  }
+  if (!name->symbol) {
+    return false;
+  } else if (name->symbol->Rank() == 0) {
+    if (const Symbol *
+        function{
+            semantics::IsFunctionResultWithSameNameAsFunction(*name->symbol)}) {
+      auto &msg{context.Say(funcRef.v.source,
+          "Recursive call to '%s' requires a distinct RESULT in its declaration"_err_en_US,
+          name->source)};
+      AttachDeclaration(&msg, *function);
+      name->symbol = const_cast<Symbol *>(function);
+    }
+    return false;
+  } else {
+    if (std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t).empty()) {
+      auto &msg{context.Say(funcRef.v.source,
+          "Reference to array '%s' with empty subscript list"_err_en_US,
+          name->source)};
+      if (name->symbol) {
         AttachDeclaration(&msg, *name->symbol);
       }
     }
+    return true;
   }
 }
 
@@ -2841,8 +2851,9 @@ static void FixMisparsedFunctionReference(
         // pointer as per C1105 so this cannot be a function reference.
         if constexpr (common::HasMember<common::Indirection<parser::Designator>,
                           uType>) {
-          CheckFuncRefToArrayElementRefHasSubscripts(context, funcRef);
-          u = common::Indirection{funcRef.ConvertToArrayElementRef()};
+          if (CheckFuncRefToArrayElement(context, funcRef)) {
+            u = common::Indirection{funcRef.ConvertToArrayElementRef()};
+          }
         } else {
           DIE("can't fix misparsed function as array reference");
         }

diff  --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index e4d1e2f09d67e..72816b7a6d897 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -1345,13 +1345,15 @@ const Symbol *FindImmediateComponent(const DerivedTypeSpec &type,
   return nullptr;
 }
 
-bool IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) {
+const Symbol *IsFunctionResultWithSameNameAsFunction(const Symbol &symbol) {
   if (IsFunctionResult(symbol)) {
     if (const Symbol * function{symbol.owner().symbol()}) {
-      return symbol.name() == function->name();
+      if (symbol.name() == function->name()) {
+        return function;
+      }
     }
   }
-  return false;
+  return nullptr;
 }
 
 void LabelEnforce::Post(const parser::GotoStmt &gotoStmt) {

diff  --git a/flang/test/Semantics/resolve59.f90 b/flang/test/Semantics/resolve59.f90
index 0eeb1170fb3d7..6f9324e36ec03 100644
--- a/flang/test/Semantics/resolve59.f90
+++ b/flang/test/Semantics/resolve59.f90
@@ -10,7 +10,7 @@ module m_no_result
   ! testing with data object results
   function f1()
     real :: x, f1
-    !ERROR: 'f1' is not a function
+    !ERROR: Recursive call to 'f1' requires a distinct RESULT in its declaration
     x = acos(f1())
     f1 = x
     x = acos(f1) !OK
@@ -18,7 +18,7 @@ function f1()
   function f2(i)
     integer i
     real :: x, f2
-    !ERROR: 'f2' is not an array
+    !ERROR: Recursive call to 'f2' requires a distinct RESULT in its declaration
     x = acos(f2(i+1))
     f2 = x
     x = acos(f2) !OK
@@ -63,7 +63,7 @@ function f6() result(f6) !OKI (warning)
   end function
   function f7() result(f7) !OKI (warning)
     real :: x, f7
-    !ERROR: 'f7' is not a function
+    !ERROR: Recursive call to 'f7' requires a distinct RESULT in its declaration
     x = acos(f7())
     f7 = x
     x = acos(f7) !OK
@@ -124,7 +124,7 @@ function f5(x) result(r)
   ! testing that calling the result is also caught
   function f6() result(r)
     real :: x, r
-    !ERROR: 'r' is not a function
+    !ERROR: 'r' is not a callable procedure
     x = r()
   end function
 end module

diff  --git a/flang/test/Semantics/resolve93.f90 b/flang/test/Semantics/resolve93.f90
index 71e0e40a2a230..a54c753657641 100644
--- a/flang/test/Semantics/resolve93.f90
+++ b/flang/test/Semantics/resolve93.f90
@@ -9,8 +9,9 @@ subroutine s1()
     character(10) str3
     !ERROR: Cannot reference function 'str1' as data
     print *, str1(1:9), str1(7)
-    !ERROR: 'str2' is not an array
-    print *, str2(1:9), str2(7)
+    print *, str2(1:9) ! substring is ok
+    !ERROR: 'str2' is not a callable procedure
+    print *, str2(7)
     !ERROR: Cannot reference function 'str3' as data
     print *, str3(7), str3(1:9)
   end block


        


More information about the flang-commits mailing list