[flang] Allow module procedure and generic with same name
authorTim Keith <tkeith@nvidia.com>
Tue, 26 Feb 2019 21:28:53 +0000 (13:28 -0800)
committerGitHub <noreply@github.com>
Thu, 28 Feb 2019 18:38:17 +0000 (10:38 -0800)
The `GenericDetails::CheckSpecific()` check was happening too early.
We have to wait until all procedures of the generic have been seen.
The generic can have the same name as a module procedure only if that
module procedure is a specific procedure of the generic.

Improve the `SayAlreadyDeclared` error message when the previous
declaration is a use-association

Original-commit: flang-compiler/f18@269e3db6020a5acc51a291dfea98455e6a97d2d5
Reviewed-on: https://github.com/flang-compiler/f18/pull/305
Tree-same-pre-rewrite: false

flang/lib/semantics/resolve-names.cc
flang/test/semantics/resolve17.f90

index 61be4a7..9e462ad 100644 (file)
@@ -414,6 +414,7 @@ public:
 
   // Special messages: already declared; referencing symbol's declaration;
   // about a type; two names & locations
+  void SayAlreadyDeclared(const SourceName &, const Symbol &);
   void SayAlreadyDeclared(const parser::Name &, const Symbol &);
   void SayWithDecl(const parser::Name &, const Symbol &, MessageFixedText &&);
   void SayDerivedType(const SourceName &, MessageFixedText &&, const Scope &);
@@ -561,7 +562,6 @@ private:
 class InterfaceVisitor : public virtual ScopeHandler {
 public:
   bool Pre(const parser::InterfaceStmt &);
-  void Post(const parser::InterfaceStmt &);
   void Post(const parser::EndInterfaceStmt &);
   bool Pre(const parser::GenericSpec &);
   bool Pre(const parser::ProcedureStmt &);
@@ -1483,9 +1483,23 @@ Bound ArraySpecVisitor::GetBound(const parser::SpecificationExpr &x) {
 
 void ScopeHandler::SayAlreadyDeclared(
     const parser::Name &name, const Symbol &prev) {
-  Say2(name, "'%s' is already declared in this scoping unit"_err_en_US, prev,
-      "Previous declaration of '%s'"_en_US);
+  SayAlreadyDeclared(name.source, prev);
 }
+void ScopeHandler::SayAlreadyDeclared(
+    const SourceName &name, const Symbol &prev) {
+  auto &msg{
+      Say(name, "'%s' is already declared in this scoping unit"_err_en_US)};
+  if (const auto *details{prev.detailsIf<UseDetails>()}) {
+    msg.Attach(details->location(),
+        "It is use-associated with '%s' in module '%s'"_err_en_US,
+        details->symbol().name().ToString().c_str(),
+        details->module().name().ToString().c_str());
+  } else {
+    msg.Attach(prev.name(), "Previous declaration of '%s'"_en_US,
+        prev.name().ToString().c_str());
+  }
+}
+
 void ScopeHandler::SayWithDecl(
     const parser::Name &name, const Symbol &symbol, MessageFixedText &&msg) {
   Say2(name, std::move(msg), symbol,
@@ -1945,15 +1959,9 @@ bool InterfaceVisitor::Pre(const parser::InterfaceStmt &x) {
   isAbstract_ = std::holds_alternative<parser::Abstract>(x.u);
   return true;
 }
-void InterfaceVisitor::Post(const parser::InterfaceStmt &) {}
 
 void InterfaceVisitor::Post(const parser::EndInterfaceStmt &) {
-  if (genericName_) {
-    if (const auto *proc{GetGenericDetails().CheckSpecific()}) {
-      SayAlreadyDeclared(*genericName_, *proc);
-    }
-    genericName_ = nullptr;
-  }
+  genericName_ = nullptr;
   inInterfaceBlock_ = false;
   isAbstract_ = false;
 }
@@ -2096,6 +2104,9 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
 void InterfaceVisitor::CheckGenericProcedures(Symbol &generic) {
   ResolveSpecificsInGeneric(generic);
   auto &details{generic.get<GenericDetails>()};
+  if (const auto *proc{details.CheckSpecific()}) {
+    SayAlreadyDeclared(generic.name(), *proc);
+  }
   auto &specifics{details.specificProcs()};
   if (specifics.empty()) {
     if (details.derivedType()) {
index 87d3eb1..a63fce0 100644 (file)
@@ -1,4 +1,4 @@
-! Copyright (c) 2018, NVIDIA CORPORATION.  All rights reserved.
+! Copyright (c) 2018-2019, NVIDIA CORPORATION.  All rights reserved.
 !
 ! Licensed under the Apache License, Version 2.0 (the "License");
 ! you may not use this file except in compliance with the License.
@@ -29,3 +29,18 @@ contains
   subroutine s
   end subroutine
 end module
+
+module m3
+  ! This is okay: so is generic and specific
+  interface s
+    procedure s2
+  end interface
+  interface s
+    procedure s
+  end interface
+contains
+  subroutine s()
+  end subroutine
+  subroutine s2(x)
+  end subroutine
+end module