[flang-commits] [flang] [flang] Emit "raw" name for procedure interface in module file (PR #83915)

via flang-commits flang-commits at lists.llvm.org
Mon Mar 4 14:06:38 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

Save both the raw procedure interface symbol as well as the result of passing it through GetUltimate() and BypassGeneric() in symbol table entries with ProcEntityDetails.  The raw symbol of the interface needs to be the one used for emitting procedure symbols to module files.

Fixes https://github.com/llvm/llvm-project/issues/83836.

---
Full diff: https://github.com/llvm/llvm-project/pull/83915.diff


14 Files Affected:

- (modified) flang/include/flang/Semantics/symbol.h (+12-6) 
- (modified) flang/lib/Evaluate/call.cpp (+1-1) 
- (modified) flang/lib/Evaluate/characteristics.cpp (+3-3) 
- (modified) flang/lib/Evaluate/shape.cpp (+1-1) 
- (modified) flang/lib/Evaluate/tools.cpp (+4-4) 
- (modified) flang/lib/Semantics/check-declarations.cpp (+3-5) 
- (modified) flang/lib/Semantics/mod-file.cpp (+5-5) 
- (modified) flang/lib/Semantics/resolve-names-utils.cpp (+3-2) 
- (modified) flang/lib/Semantics/resolve-names.cpp (+14-13) 
- (modified) flang/lib/Semantics/runtime-type-info.cpp (+1-1) 
- (modified) flang/lib/Semantics/symbol.cpp (+5-2) 
- (modified) flang/lib/Semantics/tools.cpp (+6-8) 
- (modified) flang/lib/Semantics/type.cpp (+1-1) 
- (added) flang/test/Semantics/modfile64.f90 (+29) 


``````````diff
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 125025dab5f448..794236fadbac19 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -417,8 +417,12 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg {
   ProcEntityDetails(ProcEntityDetails &&) = default;
   ProcEntityDetails &operator=(const ProcEntityDetails &) = default;
 
-  const Symbol *procInterface() const { return procInterface_; }
-  void set_procInterface(const Symbol &sym) { procInterface_ = &sym; }
+  const Symbol *rawProcInterface() const { return rawProcInterface_; }
+  const Symbol *resolvedProcInterface() const { return resolvedProcInterface_; }
+  void set_procInterfaces(const Symbol &raw, const Symbol &resolved) {
+    rawProcInterface_ = &raw;
+    resolvedProcInterface_ = &resolved;
+  }
   inline bool HasExplicitInterface() const;
 
   // Be advised: !init().has_value() => uninitialized pointer,
@@ -430,7 +434,8 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg {
   void set_isCUDAKernel(bool yes = true) { isCUDAKernel_ = yes; }
 
 private:
-  const Symbol *procInterface_{nullptr};
+  const Symbol *rawProcInterface_{nullptr};
+  const Symbol *resolvedProcInterface_{nullptr};
   std::optional<const Symbol *> init_;
   bool isCUDAKernel_{false};
   friend llvm::raw_ostream &operator<<(
@@ -909,7 +914,7 @@ class Symbol {
             },
             [](const ObjectEntityDetails &oed) { return oed.shape().Rank(); },
             [&](const ProcEntityDetails &ped) {
-              const Symbol *iface{ped.procInterface()};
+              const Symbol *iface{ped.resolvedProcInterface()};
               return iface ? iface->RankImpl(depth) : 0;
             },
             [](const AssocEntityDetails &aed) {
@@ -974,7 +979,8 @@ template <std::size_t BLOCK_SIZE> class Symbols {
 // between the two shared libraries.
 
 inline bool ProcEntityDetails::HasExplicitInterface() const {
-  return procInterface_ && procInterface_->HasExplicitInterface();
+  return resolvedProcInterface_ &&
+      resolvedProcInterface_->HasExplicitInterface();
 }
 
 inline Symbol &Symbol::GetUltimate() {
@@ -1008,7 +1014,7 @@ inline const DeclTypeSpec *Symbol::GetTypeImpl(int depth) const {
             return x.isFunction() ? x.result().GetTypeImpl(depth) : nullptr;
           },
           [&](const ProcEntityDetails &x) {
-            const Symbol *symbol{x.procInterface()};
+            const Symbol *symbol{x.resolvedProcInterface()};
             return symbol ? symbol->GetTypeImpl(depth) : x.type();
           },
           [&](const ProcBindingDetails &x) {
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index c5b50e806d2497..81626351ab9703 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -119,7 +119,7 @@ const Symbol *ProcedureDesignator::GetInterfaceSymbol() const {
   if (const Symbol * symbol{GetSymbol()}) {
     const Symbol &ultimate{symbol->GetUltimate()};
     if (const auto *proc{ultimate.detailsIf<semantics::ProcEntityDetails>()}) {
-      return proc->procInterface();
+      return proc->resolvedProcInterface();
     } else if (const auto *binding{
                    ultimate.detailsIf<semantics::ProcBindingDetails>()}) {
       return &binding->symbol();
diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 688a856220a117..313728cfd2d56a 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -85,9 +85,9 @@ std::optional<TypeAndShape> TypeAndShape::Characterize(
   return common::visit(
       common::visitors{
           [&](const semantics::ProcEntityDetails &proc) {
-            if (proc.procInterface()) {
+            if (proc.resolvedProcInterface()) {
               return Characterize(
-                  *proc.procInterface(), context, invariantOnly);
+                  *proc.resolvedProcInterface(), context, invariantOnly);
             } else if (proc.type()) {
               return Characterize(*proc.type(), context, invariantOnly);
             } else {
@@ -640,7 +640,7 @@ static std::optional<Procedure> CharacterizeProcedure(
               return intrinsic;
             }
             if (const semantics::Symbol *
-                interfaceSymbol{proc.procInterface()}) {
+                interfaceSymbol{proc.resolvedProcInterface()}) {
               auto result{
                   CharacterizeProcedure(*interfaceSymbol, context, seenProcs)};
               if (result && (IsDummy(symbol) || IsPointer(symbol))) {
diff --git a/flang/lib/Evaluate/shape.cpp b/flang/lib/Evaluate/shape.cpp
index 6246cb931ff986..551b58a9aeae1f 100644
--- a/flang/lib/Evaluate/shape.cpp
+++ b/flang/lib/Evaluate/shape.cpp
@@ -741,7 +741,7 @@ auto GetShapeHelper::operator()(const Symbol &symbol) const -> Result {
             return ScalarShape(); // no dimensions seen
           },
           [&](const semantics::ProcEntityDetails &proc) {
-            if (const Symbol * interface{proc.procInterface()}) {
+            if (const Symbol * interface{proc.resolvedProcInterface()}) {
               return (*this)(*interface);
             } else {
               return ScalarShape();
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index e7fc651b9173fe..1287b67a0a561a 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1437,9 +1437,9 @@ static bool IsPureProcedureImpl(
   }
   set.emplace(symbol);
   if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) {
-    if (procDetails->procInterface()) {
+    if (procDetails->resolvedProcInterface()) {
       // procedure with a pure interface
-      return IsPureProcedureImpl(*procDetails->procInterface(), set);
+      return IsPureProcedureImpl(*procDetails->resolvedProcInterface(), set);
     }
   } else if (const auto *details{symbol.detailsIf<ProcBindingDetails>()}) {
     return IsPureProcedureImpl(details->symbol(), set);
@@ -1509,7 +1509,7 @@ bool IsFunction(const Symbol &symbol) {
               common::visitors{
                   [](const SubprogramDetails &x) { return x.isFunction(); },
                   [](const ProcEntityDetails &x) {
-                    const Symbol *ifc{x.procInterface()};
+                    const Symbol *ifc{x.resolvedProcInterface()};
                     return x.type() || (ifc && IsFunction(*ifc));
                   },
                   [](const ProcBindingDetails &x) {
@@ -1828,7 +1828,7 @@ static const Symbol *FindFunctionResult(
                          return subp.isFunction() ? &subp.result() : nullptr;
                        },
           [&](const ProcEntityDetails &proc) {
-            const Symbol *iface{proc.procInterface()};
+            const Symbol *iface{proc.resolvedProcInterface()};
             return iface ? FindFunctionResult(*iface, seen) : nullptr;
           },
           [&](const ProcBindingDetails &binding) {
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 719bea34406aa0..fe7c83bc5b4feb 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -1195,9 +1195,7 @@ void CheckHelper::CheckArraySpec(
 void CheckHelper::CheckProcEntity(
     const Symbol &symbol, const ProcEntityDetails &details) {
   CheckSymbolType(symbol);
-  const Symbol *interface {
-    details.procInterface() ? &details.procInterface()->GetUltimate() : nullptr
-  };
+  const Symbol *interface{details.resolvedProcInterface()};
   if (details.isDummy()) {
     if (!symbol.attrs().test(Attr::POINTER) && // C843
         (symbol.attrs().test(Attr::INTENT_IN) ||
@@ -2847,8 +2845,8 @@ void CheckHelper::CheckBindC(const Symbol &symbol) {
           "An interoperable pointer must not be CONTIGUOUS"_err_en_US);
     }
   } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
-    if (!proc->procInterface() ||
-        !proc->procInterface()->attrs().test(Attr::BIND_C)) {
+    if (!proc->resolvedProcInterface() ||
+        !proc->resolvedProcInterface()->attrs().test(Attr::BIND_C)) {
       if (proc->isDummy()) {
         messages_.Say(symbol.name(),
             "A dummy procedure to an interoperable procedure must also be interoperable"_err_en_US);
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index 37fe0240537b8e..f48d85db76ddd4 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -924,8 +924,8 @@ void ModFileWriter::PutProcEntity(llvm::raw_ostream &os, const Symbol &symbol) {
       os, symbol,
       [&]() {
         os << "procedure(";
-        if (details.procInterface()) {
-          os << details.procInterface()->name();
+        if (details.rawProcInterface()) {
+          os << details.rawProcInterface()->name();
         } else if (details.type()) {
           PutType(os, *details.type());
         }
@@ -1563,7 +1563,7 @@ void SubprogramSymbolCollector::Collect() {
         // Is 's' a procedure with interface 'symbol'?
         if (s) {
           if (const auto *sDetails{s->detailsIf<ProcEntityDetails>()}) {
-            if (sDetails->procInterface() == &symbol) {
+            if (sDetails->resolvedProcInterface() == &symbol) {
               return true;
             }
           }
@@ -1622,8 +1622,8 @@ void SubprogramSymbolCollector::DoSymbol(
                       }
                     },
                     [this](const ProcEntityDetails &details) {
-                      if (details.procInterface()) {
-                        DoSymbol(*details.procInterface());
+                      if (details.rawProcInterface()) {
+                        DoSymbol(*details.rawProcInterface());
                       } else {
                         DoType(details.type());
                       }
diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp
index b901080e2860c4..801473876e7e2b 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -845,8 +845,9 @@ void SymbolMapper::MapSymbolExprs(Symbol &symbol) {
                        },
           [&](ProcEntityDetails &proc) {
             if (const Symbol *
-                mappedSymbol{MapInterface(proc.procInterface())}) {
-              proc.set_procInterface(*mappedSymbol);
+                mappedSymbol{MapInterface(proc.rawProcInterface())}) {
+              proc.set_procInterfaces(
+                  *mappedSymbol, BypassGeneric(mappedSymbol->GetUltimate()));
             } else if (const DeclTypeSpec * mappedType{MapType(proc.type())}) {
               proc.set_type(*mappedType);
             }
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 5a95d3a98992a7..78eb39ac7dce44 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2494,7 +2494,7 @@ static bool NeedsType(const Symbol &symbol) {
                         [&](const ProcEntityDetails &p) {
                           return symbol.test(Symbol::Flag::Function) &&
                               !symbol.attrs().test(Attr::INTRINSIC) &&
-                              !p.type() && !p.procInterface();
+                              !p.type() && !p.resolvedProcInterface();
                         },
                         [](const auto &) { return false; },
                     },
@@ -4963,7 +4963,7 @@ bool DeclarationVisitor::HasCycle(
     } else if (const auto *procDetails{
                    interface->detailsIf<ProcEntityDetails>()}) {
       procsInCycle.insert(*interface);
-      interface = procDetails->procInterface();
+      interface = procDetails->resolvedProcInterface();
     } else {
       break;
     }
@@ -4978,12 +4978,14 @@ Symbol &DeclarationVisitor::DeclareProcEntity(
     if (context().HasError(symbol)) {
     } else if (HasCycle(symbol, interface)) {
       return symbol;
-    } else if (interface && (details->procInterface() || details->type())) {
+    } else if (interface &&
+        (details->resolvedProcInterface() || details->type())) {
       SayWithDecl(name, symbol,
           "The interface for procedure '%s' has already been declared"_err_en_US);
       context().SetError(symbol);
     } else if (interface) {
-      details->set_procInterface(*interface);
+      details->set_procInterfaces(
+          *interface, BypassGeneric(interface->GetUltimate()));
       if (interface->test(Symbol::Flag::Function)) {
         symbol.set(Symbol::Flag::Function);
       } else if (interface->test(Symbol::Flag::Subroutine)) {
@@ -5658,10 +5660,10 @@ void DeclarationVisitor::Post(const parser::ProcInterface &x) {
 }
 void DeclarationVisitor::Post(const parser::ProcDecl &x) {
   const auto &name{std::get<parser::Name>(x.t)};
-  const Symbol *procInterface{nullptr};
-  if (interfaceName_ && interfaceName_->symbol) {
-    procInterface = &BypassGeneric(*interfaceName_->symbol);
-  }
+  // Don't use BypassGeneric or GetUltimate on this symbol, they can
+  // lead to unusable names in module files.
+  const Symbol *procInterface{
+      interfaceName_ ? interfaceName_->symbol : nullptr};
   auto attrs{HandleSaveName(name.source, GetAttrs())};
   DerivedTypeDetails *dtDetails{nullptr};
   if (Symbol * symbol{currScope().symbol()}) {
@@ -6515,7 +6517,7 @@ void DeclarationVisitor::SetType(
     }
   }
   if (auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
-    if (proc->procInterface()) {
+    if (proc->resolvedProcInterface()) {
       Say(name,
           "'%s' has an explicit interface and may not also have a type"_err_en_US);
       context().SetError(symbol);
@@ -6624,10 +6626,9 @@ void DeclarationVisitor::CheckExplicitInterface(const parser::Name &name) {
   if (const Symbol * symbol{name.symbol}) {
     const Symbol &ultimate{symbol->GetUltimate()};
     if (!context().HasError(*symbol) && !context().HasError(ultimate) &&
-        !ultimate.HasExplicitInterface()) {
+        !BypassGeneric(ultimate).HasExplicitInterface()) {
       Say(name,
-          "'%s' must be an abstract interface or a procedure with "
-          "an explicit interface"_err_en_US,
+          "'%s' must be an abstract interface or a procedure with an explicit interface"_err_en_US,
           symbol->name());
     }
   }
@@ -8292,7 +8293,7 @@ static bool NeedsExplicitType(const Symbol &symbol) {
   } else if (const auto *details{symbol.detailsIf<ObjectEntityDetails>()}) {
     return !details->type();
   } else if (const auto *details{symbol.detailsIf<ProcEntityDetails>()}) {
-    return !details->procInterface() && !details->type();
+    return !details->resolvedProcInterface() && !details->type();
   } else {
     return false;
   }
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 9845a190bc756c..c8920d7d319962 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -1253,7 +1253,7 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(
 static const DeclTypeSpec *GetDefinedIoSpecificArgType(const Symbol &specific) {
   const Symbol *interface{&specific.GetUltimate()};
   if (const auto *procEntity{specific.detailsIf<ProcEntityDetails>()}) {
-    interface = procEntity->procInterface();
+    interface = procEntity->resolvedProcInterface();
   }
   if (interface) {
     if (const SubprogramDetails *
diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index 2ab3189cf4064e..1899c69e39e701 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -451,8 +451,11 @@ llvm::raw_ostream &operator<<(
 
 llvm::raw_ostream &operator<<(
     llvm::raw_ostream &os, const ProcEntityDetails &x) {
-  if (x.procInterface_) {
-    os << ' ' << x.procInterface_->name();
+  if (x.resolvedProcInterface_) {
+    if (x.rawProcInterface_ != x.resolvedProcInterface_) {
+      os << ' ' << x.rawProcInterface_->name() << " ->";
+    }
+    os << ' ' << x.resolvedProcInterface_->name();
   } else {
     DumpType(os, x.type());
   }
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index f931ae07072010..53cecad4c31cbb 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -289,9 +289,9 @@ bool IsPointerDummy(const Symbol &symbol) {
 bool IsBindCProcedure(const Symbol &original) {
   const Symbol &symbol{original.GetUltimate()};
   if (const auto *procDetails{symbol.detailsIf<ProcEntityDetails>()}) {
-    if (procDetails->procInterface()) {
+    if (procDetails->resolvedProcInterface()) {
       // procedure component with a BIND(C) interface
-      return IsBindCProcedure(*procDetails->procInterface());
+      return IsBindCProcedure(*procDetails->resolvedProcInterface());
     }
   }
   return symbol.attrs().test(Attr::BIND_C) && IsProcedure(symbol);
@@ -465,9 +465,7 @@ const Symbol *FindInterface(const Symbol &symbol) {
   return common::visit(
       common::visitors{
           [](const ProcEntityDetails &details) {
-            const Symbol *interface {
-              details.procInterface()
-            };
+            const Symbol *interface{details.resolvedProcInterface()};
             return interface ? FindInterface(*interface) : nullptr;
           },
           [](const ProcBindingDetails &details) {
@@ -493,8 +491,8 @@ const Symbol *FindSubprogram(const Symbol &symbol) {
   return common::visit(
       common::visitors{
           [&](const ProcEntityDetails &details) -> const Symbol * {
-            if (details.procInterface()) {
-              return FindSubprogram(*details.procInterface());
+            if (details.resolvedProcInterface()) {
+              return FindSubprogram(*details.resolvedProcInterface());
             } else {
               return &symbol;
             }
@@ -775,7 +773,7 @@ const Symbol *IsFinalizable(const DerivedTypeSpec &derived,
       symbol = &binding->symbol();
     }
     if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) {
-      symbol = proc->procInterface();
+      symbol = proc->resolvedProcInterface();
     }
     if (!symbol) {
     } else if (IsElementalProcedure(*symbol)) {
diff --git a/flang/lib/Semantics/type.cpp b/flang/lib/Semantics/type.cpp
index e812283fc6f190..8bfc94e6b835cc 100644
--- a/flang/lib/Semantics/type.cpp
+++ b/flang/lib/Semantics/type.cpp
@@ -499,7 +499,7 @@ void InstantiateHelper::InstantiateComponent(const Symbol &oldSymbol) {
   } else if (auto *procDetails{newSymbol.detailsIf<ProcEntityDetails>()}) {
     // We have a procedure pointer.  Instantiate its return type
     if (const DeclTypeSpec * returnType{InstantiateType(newSymbol)}) {
-      if (!procDetails->procInterface()) {
+      if (!procDetails->resolvedProcInterface()) {
         procDetails->ReplaceType(*returnType);
       }
     }
diff --git a/flang/test/Semantics/modfile64.f90 b/flang/test/Semantics/modfile64.f90
new file mode 100644
index 00000000000000..e9df005c9ffd31
--- /dev/null
+++ b/flang/test/Semantics/modfile64.f90
@@ -0,0 +1,29 @@
+! RUN: %python %S/test_modfile.py %s %flang_fc1
+module mod0
+  interface proc
+    module procedure proc
+  end interface
+ contains
+  subroutine proc
+  end
+end
+module mod1
+  use mod0,renamed_proc=>proc
+  procedure(renamed_proc),pointer :: p
+end module
+
+!Expect: mod0.mod
+!module mod0
+!interface proc
+!procedure::proc
+!end interface
+!contains
+!subroutine proc()
+!end
+!end
+
+!Expect: mod1.mod
+!module mod1
+!use mod0,only:renamed_proc=>proc
+!procedure(renamed_proc),pointer::p
+!end

``````````

</details>


https://github.com/llvm/llvm-project/pull/83915


More information about the flang-commits mailing list