[flang] Fix use-associated procedure in generic
authorTim Keith <tkeith@nvidia.com>
Fri, 15 Jan 2021 00:31:48 +0000 (16:31 -0800)
committerTim Keith <tkeith@nvidia.com>
Fri, 15 Jan 2021 00:31:52 +0000 (16:31 -0800)
When a use-associated procedure was included in a generic, we weren't
correctly recording that fact. The ultimate symbol was added rather than
the local symbol.

Also, improve the message emitted for the specific procedure by
mentioning the module it came from.

This fixes one of the problems in https://bugs.llvm.org/show_bug.cgi?id=48648.

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

flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/modfile07.f90
flang/test/Semantics/resolve53.f90

index d66f561..cef4f00 100644 (file)
@@ -2603,36 +2603,43 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
       Say(*name, "Procedure '%s' not found"_err_en_US);
       continue;
     }
-    symbol = &symbol->GetUltimate();
     if (symbol == &generic) {
       if (auto *specific{generic.get<GenericDetails>().specific()}) {
         symbol = specific;
       }
     }
-    if (!symbol->has<SubprogramDetails>() &&
-        !symbol->has<SubprogramNameDetails>()) {
+    const Symbol &ultimate{symbol->GetUltimate()};
+    if (!ultimate.has<SubprogramDetails>() &&
+        !ultimate.has<SubprogramNameDetails>()) {
       Say(*name, "'%s' is not a subprogram"_err_en_US);
       continue;
     }
     if (kind == ProcedureKind::ModuleProcedure) {
-      if (const auto *nd{symbol->detailsIf<SubprogramNameDetails>()}) {
+      if (const auto *nd{ultimate.detailsIf<SubprogramNameDetails>()}) {
         if (nd->kind() != SubprogramKind::Module) {
           Say(*name, "'%s' is not a module procedure"_err_en_US);
         }
       } else {
         // USE-associated procedure
-        const auto *sd{symbol->detailsIf<SubprogramDetails>()};
+        const auto *sd{ultimate.detailsIf<SubprogramDetails>()};
         CHECK(sd);
-        if (symbol->owner().kind() != Scope::Kind::Module ||
+        if (ultimate.owner().kind() != Scope::Kind::Module ||
             sd->isInterface()) {
           Say(*name, "'%s' is not a module procedure"_err_en_US);
         }
       }
     }
-    if (!symbolsSeen.insert(*symbol).second) {
-      Say(name->source,
-          "Procedure '%s' is already specified in generic '%s'"_err_en_US,
-          name->source, MakeOpName(generic.name()));
+    if (!symbolsSeen.insert(ultimate).second) {
+      if (symbol == &ultimate) {
+        Say(name->source,
+            "Procedure '%s' is already specified in generic '%s'"_err_en_US,
+            name->source, MakeOpName(generic.name()));
+      } else {
+        Say(name->source,
+            "Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US,
+            ultimate.name(), ultimate.owner().GetName().value(),
+            MakeOpName(generic.name()));
+      }
       continue;
     }
     details.AddSpecificProc(*symbol, name->source);
index f3e98bf..878e342 100644 (file)
@@ -598,3 +598,29 @@ end
 ! end interface
 ! private::operator(.ne.)
 !end
+
+module m11a
+contains
+  subroutine s1()
+  end
+end
+!Expect: m11a.mod
+!module m11a
+!contains
+! subroutine s1()
+! end
+!end
+
+module m11b
+  use m11a
+  interface g
+    module procedure s1
+  end interface
+end
+!Expect: m11b.mod
+!module m11b
+! use m11a,only:s1
+! interface g
+!  procedure::s1
+! end interface
+!end
index 1487873..64b0d53 100644 (file)
@@ -471,11 +471,11 @@ end module
 subroutine s1()
   use m20
   interface operator(.not.)
-    !ERROR: Procedure 'f' is already specified in generic 'OPERATOR(.NOT.)'
+    !ERROR: Procedure 'f' from module 'm20' is already specified in generic 'OPERATOR(.NOT.)'
     procedure f
   end interface
   interface operator(+)
-    !ERROR: Procedure 'f' is already specified in generic 'OPERATOR(+)'
+    !ERROR: Procedure 'f' from module 'm20' is already specified in generic 'OPERATOR(+)'
     procedure f
   end interface
 end subroutine s1