[flang-commits] [flang] 456fdf8 - [flang] Enable more usage of generics with forward-referenced specifics in specification parts

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Aug 29 09:17:29 PDT 2023


Author: Peter Klausler
Date: 2023-08-29T09:14:23-07:00
New Revision: 456fdf851c19f79a895c59341d491ce819138522

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

LOG: [flang] Enable more usage of generics with forward-referenced specifics in specification parts

Earlier work allowed a specification expression to reference a generic function
that was defined earlier, so long as the relevant specific procedure of the
generic had been defined before the generic.  This patch extends that work
so that the generic can also be used in cases where the relevant specific
procedure has been defined after the generic and before the reference.

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

Added: 
    flang/test/Semantics/symbol29.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 92798993348aab..c7058d40d7d32d 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -135,14 +135,15 @@ class MessageHandler {
 //   + AttrsVisitor
 //   | + DeclTypeSpecVisitor
 //   |   + ImplicitRulesVisitor
-//   |     + ScopeHandler -----------+--+
-//   |       + ModuleVisitor ========|==+
-//   |       + InterfaceVisitor      |  |
-//   |       +-+ SubprogramVisitor ==|==+
-//   + ArraySpecVisitor              |  |
-//     + DeclarationVisitor <--------+  |
-//       + ConstructVisitor             |
-//         + ResolveNamesVisitor <------+
+//   |     + ScopeHandler ------------------+
+//   |       + ModuleVisitor -------------+ |
+//   |       + GenericHandler -------+    | |
+//   |       | + InterfaceVisitor    |    | |
+//   |       +-+ SubprogramVisitor ==|==+ | |
+//   + ArraySpecVisitor              |  | | |
+//     + DeclarationVisitor <--------+  | | |
+//       + ConstructVisitor             | | |
+//         + ResolveNamesVisitor <------+-+-+
 
 class BaseVisitor {
 public:
@@ -809,7 +810,23 @@ class ModuleVisitor : public virtual ScopeHandler {
       Scope *ancestor = nullptr);
 };
 
-class InterfaceVisitor : public virtual ScopeHandler {
+class GenericHandler : public virtual ScopeHandler {
+protected:
+  using ProcedureKind = parser::ProcedureStmt::Kind;
+  void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
+  void DeclaredPossibleSpecificProc(Symbol &);
+
+  // Mappings of generics to their as-yet specific proc names and kinds
+  using SpecificProcMapType =
+      std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
+  SpecificProcMapType specificsForGenericProcs_;
+  // inversion of SpecificProcMapType: maps pending proc names to generics
+  using GenericProcMapType = std::multimap<SourceName, Symbol *>;
+  GenericProcMapType genericsForSpecificProcs_;
+};
+
+class InterfaceVisitor : public virtual ScopeHandler,
+                         public virtual GenericHandler {
 public:
   bool Pre(const parser::InterfaceStmt &);
   void Post(const parser::InterfaceStmt &);
@@ -840,15 +857,7 @@ class InterfaceVisitor : public virtual ScopeHandler {
   std::stack<GenericInfo> genericInfo_;
   const GenericInfo &GetGenericInfo() const { return genericInfo_.top(); }
   void SetGenericSymbol(Symbol &symbol) { genericInfo_.top().symbol = &symbol; }
-
-  using ProcedureKind = parser::ProcedureStmt::Kind;
-  // mapping of generic to its specific proc names and kinds
-  using SpecificProcMapType =
-      std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
-  SpecificProcMapType specificProcs_;
-
   void AddSpecificProcs(const std::list<parser::Name> &, ProcedureKind);
-  void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
   void ResolveNewSpecifics();
 };
 
@@ -904,7 +913,7 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
 };
 
 class DeclarationVisitor : public ArraySpecVisitor,
-                           public virtual ScopeHandler {
+                           public virtual GenericHandler {
 public:
   using ArraySpecVisitor::Post;
   using ScopeHandler::Post;
@@ -3309,35 +3318,32 @@ bool InterfaceVisitor::isAbstract() const {
 
 void InterfaceVisitor::AddSpecificProcs(
     const std::list<parser::Name> &names, ProcedureKind kind) {
-  for (const auto &name : names) {
-    specificProcs_.emplace(
-        GetGenericInfo().symbol, std::make_pair(&name, kind));
+  if (Symbol * symbol{GetGenericInfo().symbol};
+      symbol && symbol->has<GenericDetails>()) {
+    for (const auto &name : names) {
+      specificsForGenericProcs_.emplace(symbol, std::make_pair(&name, kind));
+      genericsForSpecificProcs_.emplace(name.source, symbol);
+    }
   }
 }
 
 // By now we should have seen all specific procedures referenced by name in
 // this generic interface. Resolve those names to symbols.
-void InterfaceVisitor::ResolveSpecificsInGeneric(
+void GenericHandler::ResolveSpecificsInGeneric(
     Symbol &generic, bool isEndOfSpecificationPart) {
   auto &details{generic.get<GenericDetails>()};
   UnorderedSymbolSet symbolsSeen;
   for (const Symbol &symbol : details.specificProcs()) {
     symbolsSeen.insert(symbol.GetUltimate());
   }
-  auto range{specificProcs_.equal_range(&generic)};
+  auto range{specificsForGenericProcs_.equal_range(&generic)};
   SpecificProcMapType retain;
   for (auto it{range.first}; it != range.second; ++it) {
     const parser::Name *name{it->second.first};
     auto kind{it->second.second};
-    const Symbol *symbol{FindSymbol(*name)};
-    if (!isEndOfSpecificationPart && symbol &&
-        &symbol->owner() != &generic.owner()) {
-      // Don't mistakenly use a name from the enclosing scope while there's
-      // still a chance that it could be overridden by a later declaration in
-      // this scope.
-      retain.emplace(&generic, std::make_pair(name, kind));
-      continue;
-    }
+    const Symbol *symbol{isEndOfSpecificationPart
+            ? FindSymbol(*name)
+            : FindInScope(generic.owner(), *name)};
     ProcedureDefinitionClass defClass{ProcedureDefinitionClass::None};
     const Symbol *specific{symbol};
     const Symbol *ultimate{nullptr};
@@ -3400,8 +3406,15 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(
           MakeOpName(generic.name()));
     }
   }
-  specificProcs_.erase(range.first, range.second);
-  specificProcs_.merge(std::move(retain));
+  specificsForGenericProcs_.erase(range.first, range.second);
+  specificsForGenericProcs_.merge(std::move(retain));
+}
+
+void GenericHandler::DeclaredPossibleSpecificProc(Symbol &proc) {
+  auto range{genericsForSpecificProcs_.equal_range(proc.name())};
+  for (auto iter{range.first}; iter != range.second; ++iter) {
+    ResolveSpecificsInGeneric(*iter->second, false);
+  }
 }
 
 void InterfaceVisitor::ResolveNewSpecifics() {
@@ -4141,6 +4154,9 @@ void SubprogramVisitor::EndSubprogram(
       }
     }
   }
+  if (inInterfaceBlock() && currScope().symbol()) {
+    DeclaredPossibleSpecificProc(*currScope().symbol());
+  }
   PopScope();
 }
 
@@ -5477,6 +5493,7 @@ void DeclarationVisitor::Post(const parser::ProcDecl &x) {
   if (dtDetails) {
     dtDetails->add_component(symbol);
   }
+  DeclaredPossibleSpecificProc(symbol);
 }
 
 bool DeclarationVisitor::Pre(const parser::TypeBoundProcedurePart &) {

diff  --git a/flang/test/Semantics/symbol29.f90 b/flang/test/Semantics/symbol29.f90
new file mode 100644
index 00000000000000..1f9f78d3d83753
--- /dev/null
+++ b/flang/test/Semantics/symbol29.f90
@@ -0,0 +1,62 @@
+! RUN: %python %S/test_symbols.py %s %flang_fc1
+! References to generic functions with forward-referenced specifics.
+!DEF: /m Module
+module m
+contains
+ !DEF: /m/specific4 PUBLIC (Function) Subprogram INTEGER(4)
+ !DEF: /m/specific4/x INTENT(IN) ObjectEntity INTEGER(4)
+ integer function specific4(x)
+  !REF: /m/specific4/x
+  integer, intent(in) :: x(*)
+ end function
+ !DEF: /m/test PUBLIC (Subroutine) Subprogram
+ !DEF: /m/test/specific1 EXTERNAL (Function) Subprogram INTEGER(4)
+ subroutine test (specific1)
+  !DEF: /m/test/generic (Function) Generic
+  interface generic
+   !REF: /m/test/specific1
+   procedure :: specific1
+   !DEF: /m/test/specific2 EXTERNAL, PURE (Function) Subprogram INTEGER(4)
+   procedure :: specific2
+   !DEF: /m/test/specific3 EXTERNAL (Function) Subprogram INTEGER(4)
+   procedure :: specific3
+   !DEF: /m/test/specific4 EXTERNAL (Function) Subprogram INTEGER(4)
+   procedure :: specific4
+  end interface
+  interface
+   !REF: /m/test/specific1
+   !DEF: /m/test/specific1/x INTENT(IN) ObjectEntity INTEGER(4)
+   integer function specific1(x)
+    !REF: /m/test/specific1/x
+    integer, intent(in) :: x
+   end function
+   !REF: /m/test/specific2
+   !DEF: /m/test/specific2/x INTENT(IN) ObjectEntity INTEGER(4)
+   !DEF: /m/test/specific2/y INTENT(IN) ObjectEntity INTEGER(4)
+   pure integer function specific2(x, y)
+    !REF: /m/test/specific2/x
+    !REF: /m/test/specific2/y
+    integer, intent(in) :: x, y
+   end function
+   !REF: /m/test/specific3
+   !DEF: /m/test/specific3/x INTENT(IN) ObjectEntity INTEGER(4)
+   !DEF: /m/test/specific3/y INTENT(IN) ObjectEntity INTEGER(4)
+   integer function specific3(x, y)
+    !REF: /m/test/generic
+    import :: generic
+    !REF: /m/test/specific3/x
+    !REF: /m/test/specific3/y
+    !REF: /m/test/specific2
+    integer, intent(in) :: x, y(generic(1, x))
+   end function
+   !REF: /m/test/specific4
+   !DEF: /m/test/specific4/x INTENT(IN) ObjectEntity INTEGER(4)
+   integer function specific4(x)
+    !REF: /m/test/specific4/x
+    integer, intent(in) :: x(:)
+   end function
+  end interface
+  !REF: /m/test/specific4
+  print *, generic([1])
+ end subroutine
+end module


        


More information about the flang-commits mailing list