[flang-commits] [flang] 95199af - [flang] Local generics must not shadow host-associated generics

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Apr 14 15:48:05 PDT 2022


Author: Peter Klausler
Date: 2022-04-14T15:43:59-07:00
New Revision: 95199af4ae36c0e05714a99d084237d8e1cd14c2

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

LOG: [flang] Local generics must not shadow host-associated generics

It is possible for generic interfaces of equivalent (but not necessarily
identical -- operator(.eq.) is equivalent to operator(==)) names to
be declared in a host scope and a nested scope, and the nested declaration
should function as an extension of the host's.

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

Added: 
    flang/test/Semantics/resolve110.f90

Modified: 
    flang/lib/Semantics/resolve-names.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 6bcc89f38982a..9f7338195c09e 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6888,31 +6888,45 @@ void ResolveNamesVisitor::CreateCommonBlockSymbols(
 
 void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
   auto info{GenericSpecInfo{x}};
-  const SourceName &symbolName{info.symbolName()};
+  SourceName symbolName{info.symbolName()};
   if (IsLogicalConstant(context(), symbolName)) {
     Say(symbolName,
         "Logical constant '%s' may not be used as a defined operator"_err_en_US);
     return;
   }
   GenericDetails genericDetails;
-  if (Symbol * existing{FindInScope(symbolName)}) {
-    if (existing->has<GenericDetails>()) {
-      info.Resolve(existing);
-      return; // already have generic, add to it
+  Symbol *existing{nullptr};
+  // Check all variants of names, e.g. "operator(.ne.)" for "operator(/=)"
+  for (const std::string &n : GetAllNames(context(), symbolName)) {
+    existing = currScope().FindSymbol(n);
+    if (existing) {
+      break;
     }
+  }
+  if (existing) {
     Symbol &ultimate{existing->GetUltimate()};
-    if (auto *ultimateDetails{ultimate.detailsIf<GenericDetails>()}) {
-      // convert a use-associated generic into a local generic
-      genericDetails.CopyFrom(*ultimateDetails);
-      AddGenericUse(genericDetails, existing->name(),
-          existing->get<UseDetails>().symbol());
-    } else if (ultimate.has<SubprogramDetails>() ||
+    if (const auto *existingGeneric{ultimate.detailsIf<GenericDetails>()}) {
+      if (&ultimate.owner() != &currScope()) {
+        // Create a local copy of a host or use associated generic so that
+        // it can be locally extended without corrupting the original.
+        genericDetails.CopyFrom(*existingGeneric);
+        if (const auto *use{existing->detailsIf<UseDetails>()}) {
+          AddGenericUse(genericDetails, existing->name(), use->symbol());
+          EraseSymbol(*existing);
+        }
+        existing = &MakeSymbol(symbolName, Attrs{}, std::move(genericDetails));
+      }
+      info.Resolve(existing);
+      return;
+    }
+    if (ultimate.has<SubprogramDetails>() ||
         ultimate.has<SubprogramNameDetails>()) {
       genericDetails.set_specific(ultimate);
     } else if (ultimate.has<DerivedTypeDetails>()) {
       genericDetails.set_derivedType(ultimate);
     } else {
       SayAlreadyDeclared(symbolName, *existing);
+      return;
     }
     EraseSymbol(*existing);
   }

diff  --git a/flang/test/Semantics/resolve110.f90 b/flang/test/Semantics/resolve110.f90
new file mode 100644
index 0000000000000..398304b4d7672
--- /dev/null
+++ b/flang/test/Semantics/resolve110.f90
@@ -0,0 +1,88 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Exercise ways to define and extend non-type-bound generics
+
+module m1
+  type :: t1; end type
+  type :: t2; end type
+  interface operator(.eq.)
+    module procedure :: eq1
+  end interface
+  generic :: operator(==) => eq2
+ contains
+  logical function eq1(x, y)
+    type(t1), intent(in) :: x
+    type(t2), intent(in) :: y
+    eq1 = .true.
+  end function
+  logical function eq2(y, x)
+    type(t2), intent(in) :: y
+    type(t1), intent(in) :: x
+    eq2 = .true.
+  end function
+  subroutine test1
+    type(t1) :: a
+    type(t2) :: b
+    if (a == b .and. b .eq. a) print *, 'ok'
+  end subroutine
+end module
+
+module m2
+  use m1
+  type :: t3; end type
+  interface operator(==)
+    module procedure eq3
+  end interface
+  generic :: operator(.eq.) => eq4
+ contains
+  logical function eq3(x, y)
+    type(t1), intent(in) :: x
+    type(t3), intent(in) :: y
+    eq3 = .true.
+  end function
+  logical function eq4(y, x)
+    type(t3), intent(in) :: y
+    type(t1), intent(in) :: x
+    eq4 = .true.
+  end function
+  subroutine test2
+    type(t1) :: a
+    type(t2) :: b
+    type(t3) :: c
+    if (a == b .and. b .eq. a .and. a == c .and. c .eq. a) print *, 'ok'
+  end subroutine
+end module
+
+module m3
+  use m2
+ contains
+  logical function eq5(x, y)
+    type(t2), intent(in) :: x
+    type(t3), intent(in) :: y
+    eq5 = .true.
+  end function
+  logical function eq6(y, x)
+    type(t3), intent(in) :: y
+    type(t2), intent(in) :: x
+    eq6 = .true.
+  end function
+  subroutine test3
+    interface operator(==)
+      module procedure :: eq5
+    end interface
+    type(t1) :: a
+    type(t2) :: b
+    type(t3) :: c
+    if (a == b .and. b .eq. a .and. a == c .and. c .eq. a .and. b == c) print *, 'ok'
+    block
+      generic :: operator(.eq.) => eq6
+      if (a == b .and. b .eq. a .and. a == c .and. c .eq. a .and. b == c .and. c .eq. b) print *, 'ok'
+    end block
+   contains
+    subroutine inner
+      interface operator(.eq.)
+        module procedure :: eq6
+      end interface
+      if (a == b .and. b .eq. a .and. a == c .and. c .eq. a .and. b == c .and. c .eq. b) print *, 'ok'
+    end subroutine
+  end subroutine
+end module


        


More information about the flang-commits mailing list