[flang-commits] [flang] a3e9d3c - [flang] Allow reference to earlier generic in later interface

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Aug 8 12:19:59 PDT 2023


Author: Peter Klausler
Date: 2023-08-08T12:19:53-07:00
New Revision: a3e9d3c2c7e9f8766bf03c63e43675258cc611ee

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

LOG: [flang] Allow reference to earlier generic in later interface

Name resolutions defers all resolution and checking of specific procedures
in non-type-bound generic interfaces to the end of the specification part.
This prevents expression analysis of references to generic functions in
specification expressions in interfaces from resolving.

Example (now a new test case in modfile07.f90):
```
  module m12
    interface generic
      module procedure specific
    end interface
    interface
      module subroutine s(a1,a2)
        character(*) a1
        character(generic(a1)) a2   ! <--
      end
    end interface
   contains
    pure integer function specific(x)
      character(*), intent(in) :: x
      specific = len(x)
    end
  end
```

The solution is to partially resolve specific procedures as they are
defined for each generic, when they can be resolved, with the final
pass at the end of the specification part to finish up any forward
references and emit the necessary error messages.

Making this fix caused some issues in module file output, which have
all been resolved by making this simplifying change: generics are
now all emitted to module file specification parts as their own
group of declarations at the end of the specification part,
followed only by namelists and COMMON blocks.

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

Added: 
    

Modified: 
    flang/lib/Semantics/mod-file.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/test/Semantics/modfile07.f90
    flang/test/Semantics/modfile32.f90
    flang/test/Semantics/modfile33.f90
    flang/test/Semantics/modfile38.f90
    flang/test/Semantics/modfile39.f90
    flang/test/Semantics/modfile44.f90
    flang/test/Semantics/resolve15.f90
    flang/test/Semantics/resolve25.f90
    flang/test/Semantics/resolve77.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index c88e20965c1ebf..6671151777af46 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -271,13 +271,6 @@ void ModFileWriter::PutSymbol(
               }
             } else {
               PutGeneric(symbol);
-              if (x.specific() && &x.specific()->owner() == &symbol.owner()) {
-                PutSymbol(typeBindings, *x.specific());
-              }
-              if (x.derivedType() &&
-                  &x.derivedType()->owner() == &symbol.owner()) {
-                PutSymbol(typeBindings, *x.derivedType());
-              }
             }
           },
           [&](const UseDetails &) { PutUse(symbol); },
@@ -583,21 +576,8 @@ void ModFileWriter::PutUseExtraAttr(
   }
 }
 
-// When a generic interface has the same name as a derived type
-// in the same scope, the generic shadows the derived type.
-// If the derived type were declared first, emit the generic
-// interface at the position of derived type's declaration.
-// (ReplaceName() is not used for this purpose because doing so
-// would confusingly position error messages pertaining to the generic
-// interface upon the derived type's declaration.)
 static inline SourceName NameInModuleFile(const Symbol &symbol) {
-  if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
-    if (const auto *derivedTypeOverload{generic->derivedType()}) {
-      if (derivedTypeOverload->name().begin() < symbol.name().begin()) {
-        return derivedTypeOverload->name();
-      }
-    }
-  } else if (const auto *use{symbol.detailsIf<UseDetails>()}) {
+  if (const auto *use{symbol.detailsIf<UseDetails>()}) {
     if (use->symbol().attrs().test(Attr::PRIVATE)) {
       // Avoid the use in sorting of names created to access private
       // specific procedures as a result of generic resolution;
@@ -609,10 +589,10 @@ static inline SourceName NameInModuleFile(const Symbol &symbol) {
 }
 
 // Collect the symbols of this scope sorted by their original order, not name.
-// Namelists are an exception: they are sorted after other symbols.
+// Generics and namelists are exceptions: they are sorted after other symbols.
 void CollectSymbols(
     const Scope &scope, SymbolVector &sorted, SymbolVector &uses) {
-  SymbolVector namelist;
+  SymbolVector namelist, generics;
   std::size_t commonSize{scope.commonBlocks().size()};
   auto symbols{scope.GetSymbols()};
   sorted.reserve(symbols.size() + commonSize);
@@ -620,6 +600,15 @@ void CollectSymbols(
     if (!symbol->test(Symbol::Flag::ParentComp)) {
       if (symbol->has<NamelistDetails>()) {
         namelist.push_back(symbol);
+      } else if (const auto *generic{symbol->detailsIf<GenericDetails>()}) {
+        if (generic->specific() &&
+            &generic->specific()->owner() == &symbol->owner()) {
+          sorted.push_back(*generic->specific());
+        } else if (generic->derivedType() &&
+            &generic->derivedType()->owner() == &symbol->owner()) {
+          sorted.push_back(*generic->derivedType());
+        }
+        generics.push_back(symbol);
       } else {
         sorted.push_back(symbol);
       }
@@ -630,9 +619,12 @@ void CollectSymbols(
   }
   // Sort most symbols by name: use of Symbol::ReplaceName ensures the source
   // location of a symbol's name is the first "real" use.
-  std::sort(sorted.begin(), sorted.end(), [](SymbolRef x, SymbolRef y) {
-    return NameInModuleFile(x).begin() < NameInModuleFile(y).begin();
-  });
+  auto sorter{[](SymbolRef x, SymbolRef y) {
+    return NameInModuleFile(*x).begin() < NameInModuleFile(*y).begin();
+  }};
+  std::sort(sorted.begin(), sorted.end(), sorter);
+  std::sort(generics.begin(), generics.end(), sorter);
+  sorted.insert(sorted.end(), generics.begin(), generics.end());
   sorted.insert(sorted.end(), namelist.begin(), namelist.end());
   for (const auto &pair : scope.commonBlocks()) {
     sorted.push_back(*pair.second);

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index c22386ab83d9a2..1c568e159e9ac7 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -843,11 +843,13 @@ class InterfaceVisitor : public virtual ScopeHandler {
 
   using ProcedureKind = parser::ProcedureStmt::Kind;
   // mapping of generic to its specific proc names and kinds
-  std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>
-      specificProcs_;
+  using SpecificProcMapType =
+      std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
+  SpecificProcMapType specificProcs_;
 
   void AddSpecificProcs(const std::list<parser::Name> &, ProcedureKind);
-  void ResolveSpecificsInGeneric(Symbol &generic);
+  void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
+  void ResolveNewSpecifics();
 };
 
 class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
@@ -3258,6 +3260,7 @@ bool InterfaceVisitor::Pre(const parser::InterfaceStmt &x) {
 void InterfaceVisitor::Post(const parser::InterfaceStmt &) { EndAttrs(); }
 
 void InterfaceVisitor::Post(const parser::EndInterfaceStmt &) {
+  ResolveNewSpecifics();
   genericInfo_.pop();
 }
 
@@ -3277,11 +3280,11 @@ bool InterfaceVisitor::Pre(const parser::GenericSpec &x) {
 bool InterfaceVisitor::Pre(const parser::ProcedureStmt &x) {
   if (!isGeneric()) {
     Say("A PROCEDURE statement is only allowed in a generic interface block"_err_en_US);
-    return false;
+  } else {
+    auto kind{std::get<parser::ProcedureStmt::Kind>(x.t)};
+    const auto &names{std::get<std::list<parser::Name>>(x.t)};
+    AddSpecificProcs(names, kind);
   }
-  auto kind{std::get<parser::ProcedureStmt::Kind>(x.t)};
-  const auto &names{std::get<std::list<parser::Name>>(x.t)};
-  AddSpecificProcs(names, kind);
   return false;
 }
 
@@ -3295,6 +3298,7 @@ void InterfaceVisitor::Post(const parser::GenericStmt &x) {
   }
   const auto &names{std::get<std::list<parser::Name>>(x.t)};
   AddSpecificProcs(names, ProcedureKind::Procedure);
+  ResolveNewSpecifics();
   genericInfo_.pop();
 }
 
@@ -3318,36 +3322,48 @@ void InterfaceVisitor::AddSpecificProcs(
 
 // By now we should have seen all specific procedures referenced by name in
 // this generic interface. Resolve those names to symbols.
-void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
+void InterfaceVisitor::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)};
+  SpecificProcMapType retain;
   for (auto it{range.first}; it != range.second; ++it) {
     const parser::Name *name{it->second.first};
     auto kind{it->second.second};
-    const auto *symbol{FindSymbol(*name)};
-    if (!symbol) {
-      Say(*name, "Procedure '%s' not found"_err_en_US);
+    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;
     }
-    // Subtlety: when *symbol is a use- or host-association, the specific
-    // procedure that is recorded in the GenericDetails below must be *symbol,
-    // not the specific procedure shadowed by a generic, because that specific
-    // procedure may be a symbol from another module and its name unavailable to
-    // emit to a module file.
-    const Symbol &bypassed{BypassGeneric(*symbol)};
-    const Symbol &specific{
-        symbol == &symbol->GetUltimate() ? bypassed : *symbol};
-    const Symbol &ultimate{bypassed.GetUltimate()};
-    ProcedureDefinitionClass defClass{ClassifyProcedure(ultimate)};
+    ProcedureDefinitionClass defClass{ProcedureDefinitionClass::None};
+    const Symbol *specific{symbol};
+    const Symbol *ultimate{nullptr};
+    if (symbol) {
+      // Subtlety: when *symbol is a use- or host-association, the specific
+      // procedure that is recorded in the GenericDetails below must be *symbol,
+      // not the specific procedure shadowed by a generic, because that specific
+      // procedure may be a symbol from another module and its name unavailable
+      // to emit to a module file.
+      const Symbol &bypassed{BypassGeneric(*symbol)};
+      if (symbol == &symbol->GetUltimate()) {
+        specific = &bypassed;
+      }
+      ultimate = &bypassed.GetUltimate();
+      defClass = ClassifyProcedure(*ultimate);
+    }
+    std::optional<MessageFixedText> error;
     if (defClass == ProcedureDefinitionClass::Module) {
       // ok
     } else if (kind == ProcedureKind::ModuleProcedure) {
-      Say(*name, "'%s' is not a module procedure"_err_en_US);
-      continue;
+      error = "'%s' is not a module procedure"_err_en_US;
     } else {
       switch (defClass) {
       case ProcedureDefinitionClass::Intrinsic:
@@ -3357,47 +3373,58 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
       case ProcedureDefinitionClass::Pointer:
         break;
       case ProcedureDefinitionClass::None:
-        Say(*name, "'%s' is not a procedure"_err_en_US);
-        continue;
+        error = "'%s' is not a procedure"_err_en_US;
+        break;
       default:
-        Say(*name,
-            "'%s' is not a procedure that can appear in a generic interface"_err_en_US);
-        continue;
+        error =
+            "'%s' is not a procedure that can appear in a generic interface"_err_en_US;
+        break;
       }
     }
-    if (symbolsSeen.insert(ultimate).second /*true if added*/) {
+    if (error) {
+      if (isEndOfSpecificationPart) {
+        Say(*name, std::move(*error));
+      } else {
+        // possible forward reference, catch it later
+        retain.emplace(&generic, std::make_pair(name, kind));
+      }
+    } else if (!ultimate) {
+    } else if (symbolsSeen.insert(*ultimate).second /*true if added*/) {
       // When a specific procedure is a USE association, that association
       // is saved in the generic's specifics, not its ultimate symbol,
       // so that module file output of interfaces can distinguish them.
-      details.AddSpecificProc(specific, name->source);
-    } else if (&specific == &ultimate) {
+      details.AddSpecificProc(*specific, name->source);
+    } else if (specific == 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(),
+          ultimate->name(), ultimate->owner().GetName().value(),
           MakeOpName(generic.name()));
     }
   }
   specificProcs_.erase(range.first, range.second);
+  specificProcs_.merge(std::move(retain));
+}
+
+void InterfaceVisitor::ResolveNewSpecifics() {
+  if (Symbol * generic{genericInfo_.top().symbol};
+      generic && generic->has<GenericDetails>()) {
+    ResolveSpecificsInGeneric(*generic, false);
+  }
 }
 
 // Mixed interfaces are allowed by the standard.
 // If there is a derived type with the same name, they must all be functions.
 void InterfaceVisitor::CheckGenericProcedures(Symbol &generic) {
-  ResolveSpecificsInGeneric(generic);
+  ResolveSpecificsInGeneric(generic, true);
   auto &details{generic.get<GenericDetails>()};
   if (auto *proc{details.CheckSpecific()}) {
-    auto msg{
-        "'%s' should not be the name of both a generic interface and a"
-        " procedure unless it is a specific procedure of the generic"_warn_en_US};
-    if (proc->name().begin() > generic.name().begin()) {
-      Say(proc->name(), std::move(msg));
-    } else {
-      Say(generic.name(), std::move(msg));
-    }
+    Say(proc->name().begin() > generic.name().begin() ? proc->name()
+                                                      : generic.name(),
+        "'%s' should not be the name of both a generic interface and a procedure unless it is a specific procedure of the generic"_warn_en_US);
   }
   auto &specifics{details.specificProcs()};
   if (specifics.empty()) {

diff  --git a/flang/test/Semantics/modfile07.f90 b/flang/test/Semantics/modfile07.f90
index 48df7243e308c7..90c35a9a69377f 100644
--- a/flang/test/Semantics/modfile07.f90
+++ b/flang/test/Semantics/modfile07.f90
@@ -53,10 +53,6 @@ integer function s4(x,y)
 end
 !Expect: m1.mod
 !module m1
-! interface foo
-!  procedure::s1
-!  procedure::s2
-! end interface
 ! interface
 !  function s1(x,y)
 !   real(4),intent(in)::x
@@ -71,16 +67,6 @@ integer function s4(x,y)
 !   complex(4)::s2
 !  end
 ! end interface
-! interface operator(+)
-!  procedure::s1
-!  procedure::s2
-! end interface
-! interface operator(/=)
-!  procedure::f1
-!  procedure::f2
-!  procedure::f3
-! end interface
-! private::operator(/=)
 ! interface
 !  function f1(x,y)
 !   real(4),intent(in)::x
@@ -102,6 +88,20 @@ integer function s4(x,y)
 !   logical(4)::f3
 !  end
 ! end interface
+! interface foo
+!  procedure::s1
+!  procedure::s2
+! end interface
+! interface operator(+)
+!  procedure::s1
+!  procedure::s2
+! end interface
+! interface operator(/=)
+!  procedure::f1
+!  procedure::f2
+!  procedure::f3
+! end interface
+! private::operator(/=)
 ! interface bar
 !  procedure::s1
 !  procedure::s2
@@ -191,11 +191,11 @@ module m2b
 end
 !Expect: m2b.mod
 !module m2b
-! interface foo
-! end interface
 ! type::foo
 !  real(4)::x
 ! end type
+! interface foo
+! end interface
 ! interface bar
 ! end interface
 ! private::bar
@@ -218,9 +218,6 @@ subroutine x()
 end
 !Expect: m3.mod
 !module m3
-! interface g
-!  procedure::s1
-! end interface
 ! interface
 !  subroutine s1(f)
 !   interface
@@ -234,6 +231,9 @@ subroutine x()
 !   end interface
 !  end
 ! end interface
+! interface g
+!  procedure::s1
+! end interface
 !end
 
 module m4
@@ -250,10 +250,6 @@ subroutine s4
 end
 !Expect: m4.mod
 !module m4
-! interface foo
-!  procedure::foo
-!  procedure::f
-! end interface
 ! interface
 !  function foo()
 !   integer(4)::foo
@@ -265,6 +261,10 @@ subroutine s4
 !   integer(4)::f
 !  end
 ! end interface
+! interface foo
+!  procedure::foo
+!  procedure::f
+! end interface
 !end
 
 ! Compile contents of m4.mod and verify it gets the same thing again.
@@ -287,10 +287,6 @@ function f(x)
 end
 !Expect: m5.mod
 !module m5
-! interface foo
-!  procedure::foo
-!  procedure::f
-! end interface
 ! interface
 !  function foo()
 !   integer(4)::foo
@@ -302,6 +298,10 @@ function f(x)
 !   integer(4)::f
 !  end
 ! end interface
+! interface foo
+!  procedure::foo
+!  procedure::f
+! end interface
 !end
 
 module m6a
@@ -313,9 +313,6 @@ logical function lt(x, y)
 end
 !Expect: m6a.mod
 !module m6a
-! interface operator(<)
-!  procedure::lt
-! end interface
 ! interface
 !  function lt(x,y)
 !   logical(4),intent(in)::x
@@ -323,6 +320,9 @@ logical function lt(x, y)
 !   logical(4)::lt
 !  end
 ! end interface
+! interface operator(<)
+!  procedure::lt
+! end interface
 !end
 
 module m6b
@@ -345,10 +345,10 @@ subroutine s(x)
 end
 !Expect: m7a.mod
 !module m7a
+! private :: s
 ! interface g_integer
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  integer(4) :: x
@@ -367,10 +367,10 @@ subroutine s(x)
 end
 !Expect: m7b.mod
 !module m7b
+! private :: s
 ! interface g_real
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  real(4) :: x
@@ -401,10 +401,10 @@ subroutine test()
 !module m7c
 ! use m7a, only: g => g_integer
 ! use m7b, only: g => g_real
+! private :: s
 ! interface g
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  complex(4) :: x
@@ -427,10 +427,10 @@ subroutine s(x)
 end
 !Expect: m8a.mod
 !module m8a
+! private :: s
 ! interface g
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  integer(4) :: x
@@ -449,10 +449,10 @@ subroutine s(x)
 end
 !Expect: m8b.mod
 !module m8b
+! private :: s
 ! interface g
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  real(4) :: x
@@ -483,10 +483,10 @@ subroutine test()
 !module m8c
 ! use m8a, only: g
 ! use m8b, only: g
+! private :: s
 ! interface g
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  complex(4) :: x
@@ -509,10 +509,10 @@ subroutine s(x)
 end
 !Expect: m9a.mod
 !module m9a
+! private :: s
 ! interface g
 !  procedure :: s
 ! end interface
-! private :: s
 !contains
 ! subroutine s(x)
 !  integer(4) :: x
@@ -537,10 +537,10 @@ subroutine test()
 !Expect: m9b.mod
 !module m9b
 ! use m9a,only:g
+! private::s
 ! interface g
 !   procedure::s
 ! end interface
-! private::s
 !contains
 ! subroutine s(x)
 !   real(4)::x
@@ -624,3 +624,37 @@ module m11b
 !  procedure::s1
 ! end interface
 !end
+
+module m12
+  interface generic
+    module procedure specific
+  end interface
+  interface
+    module subroutine s(a1,a2)
+      character(*) a1
+      character(generic(a1)) a2
+    end
+  end interface
+ contains
+  pure integer function specific(x)
+    character(*), intent(in) :: x
+    specific = len(x)
+  end
+end
+!Expect: m12.mod
+!module m12
+! interface
+!  module subroutine s(a1,a2)
+!   character(*,1)::a1
+!   character(specific(a1),1)::a2
+!  end
+! end interface
+! interface generic
+!  procedure::specific
+! end interface
+!contains
+! pure function specific(x)
+!  character(*,1),intent(in)::x
+!  integer(4)::specific
+! end
+!end

diff  --git a/flang/test/Semantics/modfile32.f90 b/flang/test/Semantics/modfile32.f90
index f85eb0fa26f7fa..2878614b904160 100644
--- a/flang/test/Semantics/modfile32.f90
+++ b/flang/test/Semantics/modfile32.f90
@@ -33,11 +33,6 @@ subroutine s4(x, y, z, w, u)
 end
 !Expect: m1.mod
 !module m1
-! interface f
-!  procedure :: f1
-!  procedure :: f2
-!  procedure :: f3
-! end interface
 ! interface
 !  pure function f1(x)
 !   real(4), intent(in) :: x
@@ -60,6 +55,11 @@ subroutine s4(x, y, z, w, u)
 !   integer(8) :: f3
 !  end
 ! end interface
+! interface f
+!  procedure :: f1
+!  procedure :: f2
+!  procedure :: f3
+! end interface
 !contains
 ! subroutine s1(x, z)
 !  real(4) :: x
@@ -114,11 +114,6 @@ subroutine s3(x, y)
 end
 !Expect: m2.mod
 !module m2
-! interface f
-!  procedure :: f_real4
-!  procedure :: f_real8
-!  procedure :: f_integer
-! end interface
 ! interface
 !  pure function f_real4(x)
 !   real(4), intent(in) :: x
@@ -137,6 +132,11 @@ subroutine s3(x, y)
 !   integer(8) :: f_integer
 !  end
 ! end interface
+! interface f
+!  procedure :: f_real4
+!  procedure :: f_real8
+!  procedure :: f_integer
+! end interface
 !contains
 ! subroutine s1(x, y)
 !  real(4) :: x
@@ -243,10 +243,6 @@ subroutine s2(x, y)
 end
 !Expect: m4.mod
 !module m4
-! interface operator(.foo.)
-!  procedure :: f_real
-!  procedure :: f_integer
-! end interface
 ! interface
 !  pure function f_real(x)
 !   real(4), intent(in) :: x
@@ -259,6 +255,10 @@ subroutine s2(x, y)
 !   integer(8) :: f_integer
 !  end
 ! end interface
+! interface operator(.foo.)
+!  procedure :: f_real
+!  procedure :: f_integer
+! end interface
 !contains
 ! subroutine s1(x, y)
 !  real(4) :: x
@@ -294,10 +294,6 @@ subroutine s2(x, y)
 end
 !Expect: m5.mod
 !module m5
-! interface operator(.foo.)
-!  procedure :: f1
-!  procedure :: f2
-! end interface
 ! interface
 !  pure function f1(x, y)
 !   real(4), intent(in) :: x
@@ -312,6 +308,10 @@ subroutine s2(x, y)
 !   integer(8) :: f2
 !  end
 ! end interface
+! interface operator(.foo.)
+!  procedure :: f1
+!  procedure :: f2
+! end interface
 !contains
 ! subroutine s1(x, y)
 !  complex(4) :: x

diff  --git a/flang/test/Semantics/modfile33.f90 b/flang/test/Semantics/modfile33.f90
index 6aad8b2937b61d..98d6da402cbebc 100644
--- a/flang/test/Semantics/modfile33.f90
+++ b/flang/test/Semantics/modfile33.f90
@@ -63,11 +63,6 @@ subroutine s4(x, y, z)
 !  sequence
 !  logical(4) :: x
 ! end type
-! interface operator(+)
-!  procedure :: add_ll
-!  procedure :: add_li
-!  procedure :: add_tt
-! end interface
 ! interface
 !  pure function add_ll(x, y)
 !   logical(4), intent(in) :: x
@@ -90,10 +85,6 @@ subroutine s4(x, y, z)
 !   integer(8) :: add_tt
 !  end
 ! end interface
-! interface operator(/)
-!  procedure :: div_tz
-!  procedure :: div_ct
-! end interface
 ! interface
 !  pure function div_tz(x, y)
 !   import :: t
@@ -110,6 +101,15 @@ subroutine s4(x, y, z)
 !   integer(8) :: div_ct
 !  end
 ! end interface
+! interface operator(+)
+!  procedure :: add_ll
+!  procedure :: add_li
+!  procedure :: add_tt
+! end interface
+! interface operator(/)
+!  procedure :: div_tz
+!  procedure :: div_ct
+! end interface
 !contains
 ! subroutine s1(x, y, z)
 !  logical(4) :: x
@@ -199,11 +199,6 @@ subroutine s5(x, y, z)
 !  sequence
 !  logical(4) :: x
 ! end type
-! interface operator( .and.)
-!  procedure :: and_ti
-!  procedure :: and_li
-!  procedure :: and_tt
-! end interface
 ! interface
 !  pure function and_ti(x, y)
 !   import :: t
@@ -227,10 +222,6 @@ subroutine s5(x, y, z)
 !   integer(8) :: and_tt
 !  end
 ! end interface
-! interface operator(.x.)
-!  procedure :: neqv_tt
-!  procedure :: neqv_rr
-! end interface
 ! interface
 !  pure function neqv_tt(x, y)
 !   import :: t
@@ -246,6 +237,15 @@ subroutine s5(x, y, z)
 !   integer(8) :: neqv_rr
 !  end
 ! end interface
+! interface operator( .and.)
+!  procedure :: and_ti
+!  procedure :: and_li
+!  procedure :: and_tt
+! end interface
+! interface operator(.x.)
+!  procedure :: neqv_tt
+!  procedure :: neqv_rr
+! end interface
 !contains
 ! subroutine s1(x, y, z)
 !  type(t) :: x
@@ -323,11 +323,6 @@ subroutine s3(x, y, z)
 !  sequence
 !  logical(4) :: x
 ! end type
-! interface operator(<>)
-!  procedure :: ne_it
-!  procedure :: ne_tt
-!  procedure :: ne_ci
-! end interface
 ! interface
 !  pure function ne_it(x, y)
 !   import :: t
@@ -351,6 +346,11 @@ subroutine s3(x, y, z)
 !   integer(8) :: ne_ci
 !  end
 ! end interface
+! interface operator(<>)
+!  procedure :: ne_it
+!  procedure :: ne_tt
+!  procedure :: ne_ci
+! end interface
 !contains
 ! subroutine s1(x, y, z)
 !  integer(4) :: x
@@ -403,10 +403,6 @@ subroutine s2(x, y, z)
 !  sequence
 !  logical(4) :: x
 ! end type
-! interface operator(//)
-!  procedure :: concat_12
-!  procedure :: concat_int_real
-! end interface
 ! interface
 !  pure function concat_12(x, y)
 !   character(*, 1), intent(in) :: x
@@ -421,6 +417,10 @@ subroutine s2(x, y, z)
 !   integer(8) :: concat_int_real
 !  end
 ! end interface
+! interface operator(//)
+!  procedure :: concat_12
+!  procedure :: concat_int_real
+! end interface
 !contains
 ! subroutine s1(x, y, z)
 !  character(*, 1) :: x
@@ -480,18 +480,12 @@ subroutine s4(x, y)
 !module m5
 ! type :: t
 ! end type
-! interface operator(+)
-!  procedure :: plus_l
-! end interface
 ! interface
 !  pure function plus_l(x)
 !   logical(4), intent(in) :: x
 !   integer(8) :: plus_l
 !  end
 ! end interface
-! interface operator(-)
-!  procedure :: minus_t
-! end interface
 ! interface
 !  pure function minus_t(x)
 !   import :: t
@@ -499,10 +493,6 @@ subroutine s4(x, y)
 !   integer(8) :: minus_t
 !  end
 ! end interface
-! interface operator( .not.)
-!  procedure :: not_t
-!  procedure :: not_real
-! end interface
 ! interface
 !  pure function not_t(x)
 !   import :: t
@@ -516,6 +506,16 @@ subroutine s4(x, y)
 !   integer(8) :: not_real
 !  end
 ! end interface
+! interface operator(+)
+!  procedure :: plus_l
+! end interface
+! interface operator(-)
+!  procedure :: minus_t
+! end interface
+! interface operator( .not.)
+!  procedure :: not_t
+!  procedure :: not_real
+! end interface
 !contains
 ! subroutine s1(x, y)
 !  logical(4) :: x
@@ -556,9 +556,6 @@ subroutine s1(n, x, y, z, a, b)
 
 !Expect: m6.mod
 !module m6
-! interface operator(+)
-!  procedure :: add
-! end interface
 ! interface
 !  pure function add(x, y)
 !   real(4), intent(in) :: x(:, :)
@@ -566,6 +563,9 @@ subroutine s1(n, x, y, z, a, b)
 !   integer(8) :: add
 !  end
 ! end interface
+! interface operator(+)
+!  procedure :: add
+! end interface
 !contains
 ! subroutine s1(n, x, y, z, a, b)
 !  integer(8) :: n
@@ -610,10 +610,6 @@ subroutine s2(x, y, z)
 !  integer(4), kind :: k
 !  real(int(int(k,kind=4),kind=8))::a
 ! end type
-! interface operator(+)
-!  procedure :: f1
-!  procedure :: f2
-! end interface
 ! interface
 !  pure function f1(x, y)
 !   import :: t
@@ -630,6 +626,10 @@ subroutine s2(x, y, z)
 !   integer(8) :: f2
 !  end
 ! end interface
+! interface operator(+)
+!  procedure :: f1
+!  procedure :: f2
+! end interface
 !contains
 ! subroutine s1(x, y, z)
 !  type(t(k=4_4)) :: x

diff  --git a/flang/test/Semantics/modfile38.f90 b/flang/test/Semantics/modfile38.f90
index d2646b6ca6154b..2631357c07597c 100644
--- a/flang/test/Semantics/modfile38.f90
+++ b/flang/test/Semantics/modfile38.f90
@@ -20,14 +20,14 @@ type(t) function f
 
 !Expect: m.mod
 !module m
-!interface t
-!procedure::f
-!end interface
 !type::t
 !end type
 !type::t2
 !type(t)::c
 !end type
+!interface t
+!procedure::f
+!end interface
 !contains
 !function f()
 !type(t)::f

diff  --git a/flang/test/Semantics/modfile39.f90 b/flang/test/Semantics/modfile39.f90
index fbbd6ae4ce2993..f3b63da1400149 100644
--- a/flang/test/Semantics/modfile39.f90
+++ b/flang/test/Semantics/modfile39.f90
@@ -15,10 +15,10 @@ pure integer function priv(n)
 end module
 !Expect: m1.mod
 !module m1
+!private::priv
 !interface gen
 !procedure::priv
 !end interface
-!private::priv
 !contains
 !pure function priv(n)
 !integer(4),intent(in)::n

diff  --git a/flang/test/Semantics/modfile44.f90 b/flang/test/Semantics/modfile44.f90
index d0402b5678808b..23d93b18a5a1f4 100644
--- a/flang/test/Semantics/modfile44.f90
+++ b/flang/test/Semantics/modfile44.f90
@@ -19,12 +19,12 @@ function xzy(j) result(res)
 
 !Expect: m1.mod
 !module m1
-!interface xyz
-!procedure::xzy
-!end interface
 !type::xyz
 !integer(4)::n
 !end type
+!interface xyz
+!procedure::xzy
+!end interface
 !contains
 !function xzy(j) result(res)
 !integer(4),intent(in)::j

diff  --git a/flang/test/Semantics/resolve15.f90 b/flang/test/Semantics/resolve15.f90
index 29fcf6f7ee1532..a030d15323d41d 100644
--- a/flang/test/Semantics/resolve15.f90
+++ b/flang/test/Semantics/resolve15.f90
@@ -4,7 +4,7 @@ module m
   interface i
     !ERROR: 'var' is not a procedure
     procedure :: sub, var
-    !ERROR: Procedure 'bad' not found
+    !ERROR: 'bad' is not a procedure
     procedure :: bad
   end interface
   interface operator(.foo.)
@@ -12,7 +12,7 @@ module m
     procedure :: var
     !ERROR: OPERATOR(.foo.) procedure 'sub' must be a function
     procedure :: sub
-    !ERROR: Procedure 'bad' not found
+    !ERROR: 'bad' is not a procedure
     procedure :: bad
   end interface
 contains

diff  --git a/flang/test/Semantics/resolve25.f90 b/flang/test/Semantics/resolve25.f90
index 9e717d50cd9a6d..9311fb34b4fae0 100644
--- a/flang/test/Semantics/resolve25.f90
+++ b/flang/test/Semantics/resolve25.f90
@@ -6,7 +6,7 @@ real function s1(x)
     end
     !ERROR: 's2' is not a module procedure
     module procedure s2
-    !ERROR: Procedure 's3' not found
+    !ERROR: 's3' is not a procedure
     procedure s3
     !ERROR: Procedure 's1' is already specified in generic 'foo'
     procedure s1

diff  --git a/flang/test/Semantics/resolve77.f90 b/flang/test/Semantics/resolve77.f90
index 1f5e4d4d807193..1a76e700908161 100644
--- a/flang/test/Semantics/resolve77.f90
+++ b/flang/test/Semantics/resolve77.f90
@@ -10,7 +10,7 @@ module m
   end interface
   !ERROR: Automatic data object 'a' may not appear in the specification part of a module
   real :: a(if1(1))
-  !ERROR: No specific function of generic 'ifn2' matches the actual arguments
+  !ERROR: Automatic data object 'b' may not appear in the specification part of a module
   real :: b(ifn2(1))
  contains
   subroutine t1(n)


        


More information about the flang-commits mailing list