[flang-commits] [flang] 47995a0 - [flang] catch implicit interface incompatibility with global scope symbol

Jean Perier via flang-commits flang-commits at lists.llvm.org
Wed Feb 9 00:31:34 PST 2022


Author: Jean Perier
Date: 2022-02-09T09:30:32+01:00
New Revision: 47995a0ec92643f8b799c19103ed2c9222e63221

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

LOG: [flang] catch implicit interface incompatibility with global scope symbol

Previously, when calling a procedure implicitly for which a global scope
procedure symbol with the same name existed, semantics resolved the
procedure name in the call to the global symbol without checking that
the symbol interface was compatible with the implicit interface of the
call.
This could cause expression rewrite and lowering to later badly process
the implicit call assuming a different result type or an explicit
interface. This could lead to lowering crash in case the actual argument
were incompatible with the dummies from the explicit interface.

Emit errors in the following problematic cases:
- If the result type from the symbol did not match the one from the
  implicit interface.
- If the symbol requires an explicit interface.

This patch still allows calling an F77 like procedure with different
actual argument types than the one it was defined with because it is
correctly supported in lowering and is a feature in some program
(it is a pointer cast). The two cases that won't be accepted have
little chance to make much sense. Results returning ABIs may differ
depending on the return types, and function that requires explicit
interface usually requires descriptors or specific processing that
is incompatible with implicit interfaces.

Note that this patch is not making a deep analysis, and it will only
catch mistakes if a global symbol and an implicit interface are
involved. Cases where the user provided a conflicting explicit
interface would still require a pass after name resolution to study
conflicts more deeply. But these cases will not crash lowering or
trigger expression rewrite to do weird things.

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

Added: 
    flang/test/Semantics/call24.f90

Modified: 
    flang/lib/Semantics/expression.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/test/Semantics/resolve89.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index d031993603c1..7b8da73f404c 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2483,7 +2483,7 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
     bool treatExternalAsImplicit{IsExternalCalledImplicitly(callSite, proc)};
     if (treatExternalAsImplicit && !chars->CanBeCalledViaImplicitInterface()) {
       Say(callSite,
-          "References to the procedure '%s' require an explicit interface"_en_US,
+          "References to the procedure '%s' require an explicit interface"_err_en_US,
           DEREF(proc.GetSymbol()).name());
     }
     // Checks for ASSOCIATED() are done in intrinsic table processing

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index a77d3c83cb2c..4308260e9fb7 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6462,6 +6462,18 @@ void ResolveNamesVisitor::NoteExecutablePartCall(
   }
 }
 
+static bool IsLocallyImplicitGlobalSymbol(
+    const Symbol &symbol, const parser::Name &localName) {
+  return symbol.owner().IsGlobal() &&
+      (!symbol.scope() ||
+          !symbol.scope()->sourceRange().Contains(localName.source));
+}
+
+static bool TypesMismatchIfNonNull(
+    const DeclTypeSpec *type1, const DeclTypeSpec *type2) {
+  return type1 && type2 && *type1 != *type2;
+}
+
 // Check and set the Function or Subroutine flag on symbol; false on error.
 bool ResolveNamesVisitor::SetProcFlag(
     const parser::Name &name, Symbol &symbol, Symbol::Flag flag) {
@@ -6474,6 +6486,12 @@ bool ResolveNamesVisitor::SetProcFlag(
     SayWithDecl(
         name, symbol, "Cannot call subroutine '%s' like a function"_err_en_US);
     return false;
+  } else if (flag == Symbol::Flag::Function &&
+      IsLocallyImplicitGlobalSymbol(symbol, name) &&
+      TypesMismatchIfNonNull(symbol.GetType(), GetImplicitType(symbol))) {
+    SayWithDecl(name, symbol,
+        "Implicit declaration of function '%s' has a 
diff erent result type than in previous declaration"_err_en_US);
+    return false;
   } else if (symbol.has<ProcEntityDetails>()) {
     symbol.set(flag); // in case it hasn't been set yet
     if (flag == Symbol::Flag::Function) {

diff  --git a/flang/test/Semantics/call24.f90 b/flang/test/Semantics/call24.f90
new file mode 100644
index 000000000000..9013a3f621b2
--- /dev/null
+++ b/flang/test/Semantics/call24.f90
@@ -0,0 +1,26 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! 15.4.2.2. Test that errors are reported when an explicit interface
+! is not provided for an external procedure that requires an explicit
+! interface (the definition needs to be visible so that the compiler
+! can detect the violation).
+
+subroutine foo(a_pointer)
+  real, pointer :: a_pointer(:)
+end subroutine
+
+subroutine test()
+  real, pointer :: a_pointer(:)
+  real, pointer :: an_array(:)
+
+  ! This call would be allowed if the interface was explicit here,
+  ! but its handling with an implicit interface is 
diff erent (no
+  ! descriptor involved, copy-in/copy-out...)
+
+  !ERROR: References to the procedure 'foo' require an explicit interface
+  call foo(a_pointer)
+
+  ! This call would be error if the interface was explicit here.
+
+  !ERROR: References to the procedure 'foo' require an explicit interface
+  call foo(an_array)
+end subroutine

diff  --git a/flang/test/Semantics/resolve89.f90 b/flang/test/Semantics/resolve89.f90
index a15e54578589..e929536b8b36 100644
--- a/flang/test/Semantics/resolve89.f90
+++ b/flang/test/Semantics/resolve89.f90
@@ -16,11 +16,11 @@ impure function impureFunc()
   impureFunc = 3
 end function impureFunc
 
-pure function pureFunc()
-  integer :: pureFunc
+pure function iPureFunc()
+  integer :: iPureFunc
 
-  pureFunc = 3
-end function pureFunc
+  iPureFunc = 3
+end function iPureFunc
 
 module m
   real, allocatable :: mVar
@@ -49,7 +49,7 @@ subroutine s(iArg, allocArg, pointerArg, arrayArg, ioArg, optionalArg)
   ! statement functions referenced below
   iVolatileStmtFunc() = 3 * volatileVar
   iImpureStmtFunc() = 3 * impureFunc()
-  iPureStmtFunc() = 3 * pureFunc()
+  iPureStmtFunc() = 3 * iPureFunc()
 
   ! This is OK
   real, dimension(merge(1, 2, allocated(mVar))) :: rVar


        


More information about the flang-commits mailing list