[llvm-branch-commits] [flang] 18278ff - [flang] Fix accessibility of USEd name in .mod file

2021-01-13 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2021-01-13T12:52:44-08:00
New Revision: 18278ff1aac47d9bffa0231c74277ffc89def13e

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

LOG: [flang] Fix accessibility of USEd name in .mod file

If a module specifies default private accessibility, names that have
been use-associated are private by default. This was not reflected in
.mod files.

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

Added: 


Modified: 
flang/lib/Semantics/mod-file.cpp
flang/test/Semantics/modfile03.f90

Removed: 




diff  --git a/flang/lib/Semantics/mod-file.cpp 
b/flang/lib/Semantics/mod-file.cpp
index f8e5889e4698..23733f944d8c 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -427,6 +427,7 @@ void ModFileWriter::PutUse(const Symbol &symbol) {
 PutGenericName(uses_ << "=>", use);
   }
   uses_ << '\n';
+  PutUseExtraAttr(Attr::PRIVATE, symbol, use);
   PutUseExtraAttr(Attr::VOLATILE, symbol, use);
   PutUseExtraAttr(Attr::ASYNCHRONOUS, symbol, use);
 }

diff  --git a/flang/test/Semantics/modfile03.f90 
b/flang/test/Semantics/modfile03.f90
index 9bdb35695f03..a4b21c8287f5 100644
--- a/flang/test/Semantics/modfile03.f90
+++ b/flang/test/Semantics/modfile03.f90
@@ -158,3 +158,21 @@ subroutine s(x)
 !  end
 ! end interface
 !end
+
+module m7a
+  real :: x
+end
+!Expect: m7a.mod
+!module m7a
+! real(4)::x
+!end
+
+module m7b
+  use m7a
+  private
+end
+!Expect: m7b.mod
+!module m7b
+! use m7a,only:x
+! private::x
+!end



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] 3e41ab1 - [flang] Fix dangling pointer in LabelEnforce

2021-01-14 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2021-01-14T06:52:21-08:00
New Revision: 3e41ab18db2255028c288a11665c08d260654299

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

LOG: [flang] Fix dangling pointer in LabelEnforce

`DirectiveStructureChecker` was passing in a pointer to a temporary
string for the `construct` argument to the constructor for `LabelEnforce`.
The `LabelEnforce` object had a lifetime longer than the temporary,
resulting in accessing a dangling pointer when emitting an error message
for `omp-parallell01.f90`.

The fix is to make the lifetime of the temporary as long as the lifetime
of the `LabelEnforce` object.

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

Added: 


Modified: 
flang/lib/Semantics/check-directive-structure.h

Removed: 




diff  --git a/flang/lib/Semantics/check-directive-structure.h 
b/flang/lib/Semantics/check-directive-structure.h
index 1075087feb4f..76157ac93925 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -280,9 +280,9 @@ void DirectiveStructureChecker::CheckNoBranching(
   context_, directiveSource, directive, ContextDirectiveAsFortran()};
   parser::Walk(block, noBranchingEnforce);
 
+  auto 
construct{parser::ToUpperCaseLetters(getDirectiveName(directive).str())};
   LabelEnforce directiveLabelEnforce{context_, noBranchingEnforce.labels(),
-  directiveSource,
-  parser::ToUpperCaseLetters(getDirectiveName(directive).str()).c_str()};
+  directiveSource, construct.c_str()};
   parser::Walk(block, directiveLabelEnforce);
 }
 



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] d6acf3c - [flang] Fix use-associated procedure in generic

2021-01-14 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2021-01-14T16:31:52-08:00
New Revision: d6acf3c2012b00f06a422e8704609676be7729b2

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

LOG: [flang] Fix use-associated procedure in generic

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

Added: 


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

Removed: 




diff  --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index d66f561fc3c5..cef4f0010302 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -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().specific()}) {
 symbol = specific;
   }
 }
-if (!symbol->has() &&
-!symbol->has()) {
+const Symbol &ultimate{symbol->GetUltimate()};
+if (!ultimate.has() &&
+!ultimate.has()) {
   Say(*name, "'%s' is not a subprogram"_err_en_US);
   continue;
 }
 if (kind == ProcedureKind::ModuleProcedure) {
-  if (const auto *nd{symbol->detailsIf()}) {
+  if (const auto *nd{ultimate.detailsIf()}) {
 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()};
+const auto *sd{ultimate.detailsIf()};
 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);

diff  --git a/flang/test/Semantics/modfile07.f90 
b/flang/test/Semantics/modfile07.f90
index f3e98bf195f9..878e342ff16a 100644
--- a/flang/test/Semantics/modfile07.f90
+++ b/flang/test/Semantics/modfile07.f90
@@ -598,3 +598,29 @@ module m10d
 ! 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

diff  --git a/flang/test/Semantics/resolve53.f90 
b/flang/test/Semantics/resolve53.f90
index 1487873bd86b..64b0d536fa17 100644
--- a/flang/test/Semantics/resolve53.f90
+++ b/flang/test/Semantics/resolve53.f90
@@ -471,11 +471,11 @@ real function f(x)
 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



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] f782d5e - [flang] Detect call to abstract interface

2020-12-28 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-28T16:36:34-08:00
New Revision: f782d5ea86f6fc82b51a0de688bf292f39cc4814

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

LOG: [flang] Detect call to abstract interface

A subroutine call or function reference to an abstract interface is
not legal.

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

Added: 


Modified: 
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/resolve20.f90

Removed: 




diff  --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index 73c624aefa22..2412758f340b 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5879,7 +5879,10 @@ void ResolveNamesVisitor::HandleProcedureName(
   return; // reported error
 }
 CheckImplicitNoneExternal(name.source, *symbol);
-if (IsProcedure(*symbol) || symbol->has() ||
+if (symbol->has() &&
+symbol->attrs().test(Attr::ABSTRACT)) {
+  Say(name, "Abstract interface '%s' may not be called"_err_en_US);
+} else if (IsProcedure(*symbol) || symbol->has() ||
 symbol->has() ||
 symbol->has()) {
   // Symbols with DerivedTypeDetails, ObjectEntityDetails and

diff  --git a/flang/test/Semantics/resolve20.f90 
b/flang/test/Semantics/resolve20.f90
index f9cfc7cb1006..94bd4c18a6a0 100644
--- a/flang/test/Semantics/resolve20.f90
+++ b/flang/test/Semantics/resolve20.f90
@@ -61,7 +61,18 @@ subroutine forward
 procedure(proc), deferred :: p1
   end type t1
 
+  abstract interface
+function f()
+end function
+  end interface
+
 contains
   subroutine bar
   end subroutine
+  subroutine test
+!ERROR: Abstract interface 'foo' may not be called
+call foo()
+!ERROR: Abstract interface 'f' may not be called
+x = f()
+  end subroutine
 end module



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] 3a0352b - [flang] Fix bug with USE of USE of generic

2020-12-15 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-15T16:11:59-08:00
New Revision: 3a0352b85c14cb83150df62a9ea9ac3c4129060d

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

LOG: [flang] Fix bug with USE of USE of generic

When merging use associations into a generic, we weren't handling
the case where the name that was use associated was itself a use
association. This is fixed by following that association to its
ultimate symbol (`useUltimate` in `DoAddUse`).

An example of the bug is `m12d` in `resolve17.f90`. `g` is associated
with `gc` in `m12c` which is associated with `gb` in `m12b`. It was that
last association that we weren't correctly following.

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

Added: 


Modified: 
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/symbol.cpp
flang/test/Semantics/resolve17.f90

Removed: 




diff  --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index b0e0b0b80ebf..5ac787b61d68 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -2371,38 +2371,40 @@ void ModuleVisitor::DoAddUse(const SourceName &location,
 const SourceName &localName, Symbol &localSymbol, const Symbol &useSymbol) 
{
   localSymbol.attrs() = useSymbol.attrs() & ~Attrs{Attr::PUBLIC, 
Attr::PRIVATE};
   localSymbol.flags() = useSymbol.flags();
+  const Symbol &useUltimate{useSymbol.GetUltimate()};
   if (auto *useDetails{localSymbol.detailsIf()}) {
-const Symbol &ultimate{localSymbol.GetUltimate()};
-if (ultimate == useSymbol.GetUltimate()) {
+const Symbol &localUltimate{localSymbol.GetUltimate()};
+if (localUltimate == useUltimate) {
   // use-associating the same symbol again -- ok
-} else if (ultimate.has() &&
-useSymbol.has()) {
+} else if (localUltimate.has() &&
+useUltimate.has()) {
   // use-associating generics with the same names: merge them into a
   // new generic in this scope
-  auto generic1{ultimate.get()};
-  AddGenericUse(generic1, localName, useSymbol);
+  auto generic1{localUltimate.get()};
+  AddGenericUse(generic1, localName, useUltimate);
   generic1.AddUse(localSymbol);
   // useSymbol has specific g and so does generic1
-  auto &generic2{useSymbol.get()};
+  auto &generic2{useUltimate.get()};
   if (generic1.derivedType() && generic2.derivedType() &&
   generic1.derivedType() != generic2.derivedType()) {
 Say(location,
 "Generic interface '%s' has ambiguous derived types"
 " from modules '%s' and '%s'"_err_en_US,
 localSymbol.name(), GetUsedModule(*useDetails).name(),
-useSymbol.owner().GetName().value());
+useUltimate.owner().GetName().value());
 context().SetError(localSymbol);
   } else {
 generic1.CopyFrom(generic2);
   }
   EraseSymbol(localSymbol);
-  MakeSymbol(localSymbol.name(), ultimate.attrs(), std::move(generic1));
+  MakeSymbol(
+  localSymbol.name(), localUltimate.attrs(), std::move(generic1));
 } else {
   ConvertToUseError(localSymbol, location, *useModuleScope_);
 }
   } else if (auto *genericDetails{localSymbol.detailsIf()}) {
-if (const auto *useDetails{useSymbol.detailsIf()}) {
-  AddGenericUse(*genericDetails, localName, useSymbol);
+if (const auto *useDetails{useUltimate.detailsIf()}) {
+  AddGenericUse(*genericDetails, localName, useUltimate);
   if (genericDetails->derivedType() && useDetails->derivedType() &&
   genericDetails->derivedType() != useDetails->derivedType()) {
 Say(location,

diff  --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp
index ee6a4a15de83..656c993935cd 100644
--- a/flang/lib/Semantics/symbol.cpp
+++ b/flang/lib/Semantics/symbol.cpp
@@ -431,8 +431,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const 
Details &details) {
   },
   [&](const UseErrorDetails &x) {
 os << " uses:";
+char sep{':'};
 for (const auto &[location, module] : x.occurrences()) {
-  os << " from " << module->GetName().value() << " at " << 
location;
+  os << sep << " from " << module->GetName().value() << " at "
+ << location;
+  sep = ',';
 }
   },
   [](const HostAssocDetails &) {},

diff  --git a/flang/test/Semantics/resolve17.f90 
b/flang/test/Semantics/resolve17.f90
index 5aedaaa62003..2a2688749209 100644
--- a/flang/test/Semantics/resolve17.f90
+++ b/flang/test/Semantics/resolve17.f90
@@ -238,3 +238,30 @@ module m11c
   !ERROR: Generic interface 'g' has ambiguous derived types from modules 
'm11a' and 'm11b'
   use m11b
 e

[llvm-branch-commits] [flang] 7082de5 - [flang] Handle multiple names for same operator

2020-12-16 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-16T07:06:55-08:00
New Revision: 7082de56b7ad4b4eeb75e59e0d4c28bed44b5d23

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

LOG: [flang] Handle multiple names for same operator

Some operators have more than one name, e.g. operator(==), operator(.eq).
That was working correctly in generic definitions but they can also
appear in other contexts: USE statements and access statements, for
example.

This changes FindInScope to always look for each of the names for
a symbol. So an operator may be use-associated under one name but
declared private under another name and it will be the same symbol.
This replaces GenericSpecInfo::FindInScope which was only usable in
some cases.

Add a version of FindInScope() that looks in the current scope to
simplify many of the calls.

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

Added: 


Modified: 
flang/lib/Semantics/resolve-names-utils.cpp
flang/lib/Semantics/resolve-names-utils.h
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/modfile07.f90

Removed: 




diff  --git a/flang/lib/Semantics/resolve-names-utils.cpp 
b/flang/lib/Semantics/resolve-names-utils.cpp
index 8dbd25e163ac..83bff78f426a 100644
--- a/flang/lib/Semantics/resolve-names-utils.cpp
+++ b/flang/lib/Semantics/resolve-names-utils.cpp
@@ -29,6 +29,8 @@ using common::NumericOperator;
 using common::RelationalOperator;
 using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator;
 
+static constexpr const char *operatorPrefix{"operator("};
+
 static GenericKind MapIntrinsicOperator(IntrinsicOperator);
 
 Symbol *Resolve(const parser::Name &name, Symbol *symbol) {
@@ -65,6 +67,37 @@ bool IsIntrinsicOperator(
   return false;
 }
 
+template 
+std::forward_list GetOperatorNames(
+const SemanticsContext &context, E opr) {
+  std::forward_list result;
+  for (const char *name : context.languageFeatures().GetNames(opr)) {
+result.emplace_front(std::string{operatorPrefix} + name + ')');
+  }
+  return result;
+}
+
+std::forward_list GetAllNames(
+const SemanticsContext &context, const SourceName &name) {
+  std::string str{name.ToString()};
+  if (!name.empty() && name.end()[-1] == ')' &&
+  name.ToString().rfind(std::string{operatorPrefix}, 0) == 0) {
+for (int i{0}; i != common::LogicalOperator_enumSize; ++i) {
+  auto names{GetOperatorNames(context, LogicalOperator{i})};
+  if (std::find(names.begin(), names.end(), str) != names.end()) {
+return names;
+  }
+}
+for (int i{0}; i != common::RelationalOperator_enumSize; ++i) {
+  auto names{GetOperatorNames(context, RelationalOperator{i})};
+  if (std::find(names.begin(), names.end(), str) != names.end()) {
+return names;
+  }
+}
+  }
+  return {str};
+}
+
 bool IsLogicalConstant(
 const SemanticsContext &context, const SourceName &name) {
   std::string str{name.ToString()};
@@ -73,37 +106,6 @@ bool IsLogicalConstant(
   (str == ".t" || str == ".f."));
 }
 
-// The operators <, <=, >, >=, ==, and /= always have the same interpretations
-// as the operators .LT., .LE., .GT., .GE., .EQ., and .NE., respectively.
-std::forward_list GenericSpecInfo::GetAllNames(
-SemanticsContext &context) const {
-  auto getNames{[&](auto opr) {
-std::forward_list result;
-for (const char *name : context.languageFeatures().GetNames(opr)) {
-  result.emplace_front("operator("s + name + ')');
-}
-return result;
-  }};
-  return std::visit(
-  common::visitors{[&](const LogicalOperator &x) { return getNames(x); },
-  [&](const RelationalOperator &x) { return getNames(x); },
-  [&](const auto &) -> std::forward_list {
-return {symbolName_.value().ToString()};
-  }},
-  kind_.u);
-}
-
-Symbol *GenericSpecInfo::FindInScope(
-SemanticsContext &context, const Scope &scope) const {
-  for (const auto &name : GetAllNames(context)) {
-auto iter{scope.find(SourceName{name})};
-if (iter != scope.end()) {
-  return &*iter->second;
-}
-  }
-  return nullptr;
-}
-
 void GenericSpecInfo::Resolve(Symbol *symbol) const {
   if (symbol) {
 if (auto *details{symbol->detailsIf()}) {
@@ -162,6 +164,16 @@ void GenericSpecInfo::Analyze(const parser::GenericSpec 
&x) {
   x.u);
 }
 
+llvm::raw_ostream &operator<<(
+llvm::raw_ostream &os, const GenericSpecInfo &info) {
+  os << "GenericSpecInfo: kind=" << info.kind_.ToString();
+  os << " parseName="
+ << (info.parseName_ ? info.parseName_->ToString() : "null");
+  os << " symbolName="
+ << (info.symbolName_ ? info.symbolName_->ToString() : "null");
+  return os;
+}
+
 // parser::DefinedOperator::IntrinsicOperator -> GenericKind
 static GenericKind MapIntrinsicOperator(Intrinsic

[llvm-branch-commits] [flang] f6b577e - [flang] Fix -intrinsic-module-directory in flang script

2020-12-17 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-17T19:08:19-08:00
New Revision: f6b577ed5bf61078cdcf60e94867b75c94f540a7

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

LOG: [flang] Fix -intrinsic-module-directory in flang script

The flang wrapper script that was created as bin/flang in an in-tree
build did not have a correct -intrinsic-module-directory option.
It was correct for out-of-tree builds and for both kinds of installs.

The fix is to pick the correct directory based on what exists.

The script is no longer configured by cmake (just copied) so that
mechanism can be deleted from the cmake file.

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

Added: 
flang/tools/f18/flang

Modified: 
flang/tools/f18/CMakeLists.txt

Removed: 
flang/tools/f18/flang.sh.in



diff  --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt
index cdc09fc7a68a..8f30bfa47b79 100644
--- a/flang/tools/f18/CMakeLists.txt
+++ b/flang/tools/f18/CMakeLists.txt
@@ -65,28 +65,12 @@ add_custom_target(module_files ALL DEPENDS ${MODULE_FILES})
 
 install(TARGETS f18 DESTINATION bin)
 
-set(FLANG_INTRINSIC_MODULES_DIR ${FLANG_BINARY_DIR}/include/flang)
-
 # This flang shell script will only work in a POSIX shell.
 if (NOT WIN32)
-  if (FLANG_STANDALONE_BUILD)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in 
${CMAKE_BINARY_DIR}/tools/flang/bin/flang @ONLY)
-file(COPY ${CMAKE_BINARY_DIR}/tools/flang/bin/flang DESTINATION 
${CMAKE_BINARY_DIR}/bin FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE)
-  else()
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in
-  ${CMAKE_CURRENT_BINARY_DIR}/tools/flang/bin/flang @ONLY)
-add_custom_command(TARGET f18
-POST_BUILD
-  COMMAND ${CMAKE_COMMAND} -E copy
-  ${CMAKE_CURRENT_BINARY_DIR}/tools/flang/bin/flang
-  ${LLVM_RUNTIME_OUTPUT_INTDIR}/flang
-COMMAND chmod +x ${LLVM_RUNTIME_OUTPUT_INTDIR}/flang)
-  endif()
+  file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/flang
+DESTINATION ${CMAKE_BINARY_DIR}/bin
+FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE)
+  install(PROGRAMS ${CMAKE_BINARY_DIR}/bin/flang DESTINATION bin)
 endif()
 
-# The flang script to be installed needs a 
diff erent path to the headers.
-set(FLANG_INTRINSIC_MODULES_DIR ${CMAKE_INSTALL_PREFIX}/include/flang)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in 
${FLANG_BINARY_DIR}/bin/flang-install.sh @ONLY)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/f18_version.h.in 
${CMAKE_CURRENT_BINARY_DIR}/f18_version.h @ONLY)
-
-install(PROGRAMS ${FLANG_BINARY_DIR}/bin/flang-install.sh DESTINATION bin 
RENAME flang)

diff  --git a/flang/tools/f18/flang b/flang/tools/f18/flang
new file mode 100644
index ..01bdffdd20c7
--- /dev/null
+++ b/flang/tools/f18/flang
@@ -0,0 +1,15 @@
+#!/bin/bash
+#===-- tools/f18/flang.sh -*- sh 
-*-===#
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#======#
+
+wd=$(cd $(dirname "$0")/.. && pwd)
+module_dir=$wd/include/flang
+if [[ ! -d $module_dir ]]; then
+  module_dir=$wd/tools/flang/include/flang
+fi
+$wd/bin/f18 -module-suffix .f18.mod -intrinsic-module-directory $module_dir 
"$@"

diff  --git a/flang/tools/f18/flang.sh.in b/flang/tools/f18/flang.sh.in
deleted file mode 100644
index 295d93abbeb6..
--- a/flang/tools/f18/flang.sh.in
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-#===-- tools/f18/flang.sh -*- sh 
-*-===#
-#
-# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-# See https://llvm.org/LICENSE.txt for license information.
-# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#
-#======#
-
-function abspath() {
-  pushd . > /dev/null;
-  if [ -d "$1" ]; then
-cd "$1";
-dirs -l +0;
-  else
-cd "`dirname \"$1\"`";
-cur_dir=`dirs -l +0`;
-if [ "$cur_dir" == "/" ]; then
-  echo "$cur_dir`basename \"$1\"`";
-else
-  echo "$cur_dir/`basename \"$1\"`";
-fi;
-  fi;
-  popd > /dev/null;
-}
-
-wd=`abspath $(dirname "$0")/..`
-
-${wd}/bin/f18 -module-suffix .f18.mod -intrinsic-module-directory 
${wd}/include/flang $*



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] bf0870d - [flang] Fix bug in IMPLICIT NONE(EXTERNAL)

2020-12-18 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-18T17:43:53-08:00
New Revision: bf0870d8640df27b6bb082de0347008240cb0e67

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

LOG: [flang] Fix bug in IMPLICIT NONE(EXTERNAL)

We were only checking the restrictions of IMPLICIT NONE(EXTERNAL) when a
procedure name is first encountered. But it can also happen with an
existing symbol, e.g. if an external function's return type is declared
before is it called. This change adds a check in that branch too.

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

Added: 


Modified: 
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/implicit07.f90

Removed: 




diff  --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index 495d7d0f8584..8d5284131cc0 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1364,6 +1364,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
   void CheckImport(const SourceName &, const SourceName &);
   void HandleCall(Symbol::Flag, const parser::Call &);
   void HandleProcedureName(Symbol::Flag, const parser::Name &);
+  bool CheckImplicitNoneExternal(const SourceName &, const Symbol &);
   bool SetProcFlag(const parser::Name &, Symbol &, Symbol::Flag);
   void ResolveSpecificationParts(ProgramTree &);
   void AddSubpNames(ProgramTree &);
@@ -5853,10 +5854,7 @@ void ResolveNamesVisitor::HandleProcedureName(
   return;
 }
 if (!symbol->attrs().test(Attr::INTRINSIC)) {
-  if (isImplicitNoneExternal() && !symbol->attrs().test(Attr::EXTERNAL)) {
-Say(name,
-"'%s' is an external procedure without the EXTERNAL"
-" attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
+  if (!CheckImplicitNoneExternal(name.source, *symbol)) {
 return;
   }
   MakeExternal(*symbol);
@@ -5877,6 +5875,7 @@ void ResolveNamesVisitor::HandleProcedureName(
 if (!SetProcFlag(name, *symbol, flag)) {
   return; // reported error
 }
+CheckImplicitNoneExternal(name.source, *symbol);
 if (IsProcedure(*symbol) || symbol->has() ||
 symbol->has() ||
 symbol->has()) {
@@ -5895,6 +5894,18 @@ void ResolveNamesVisitor::HandleProcedureName(
   }
 }
 
+bool ResolveNamesVisitor::CheckImplicitNoneExternal(
+const SourceName &name, const Symbol &symbol) {
+  if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL) &&
+  !symbol.attrs().test(Attr::INTRINSIC) && !symbol.HasExplicitInterface()) 
{
+Say(name,
+"'%s' is an external procedure without the EXTERNAL"
+" attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
+return false;
+  }
+  return true;
+}
+
 // Variant of HandleProcedureName() for use while skimming the executable
 // part of a subprogram to catch calls to dummy procedures that are part
 // of the subprogram's interface, and to mark as procedures any symbols

diff  --git a/flang/test/Semantics/implicit07.f90 
b/flang/test/Semantics/implicit07.f90
index df015f7bcc62..5362f91dcb02 100644
--- a/flang/test/Semantics/implicit07.f90
+++ b/flang/test/Semantics/implicit07.f90
@@ -1,9 +1,12 @@
 ! RUN: %S/test_errors.sh %s %t %f18
 implicit none(external)
 external x
+integer :: f, i
 call x
 !ERROR: 'y' is an external procedure without the EXTERNAL attribute in a scope 
with IMPLICIT NONE(EXTERNAL)
 call y
+!ERROR: 'f' is an external procedure without the EXTERNAL attribute in a scope 
with IMPLICIT NONE(EXTERNAL)
+i = f()
 block
   !ERROR: 'z' is an external procedure without the EXTERNAL attribute in a 
scope with IMPLICIT NONE(EXTERNAL)
   call z



___
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits


[llvm-branch-commits] [flang] d55627d - [flang] Fix bugs in .mod file for abstract interface

2020-12-28 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-28T08:50:32-08:00
New Revision: d55627d221be8154cbdf454fa727afcc3f716b08

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

LOG: [flang] Fix bugs in .mod file for abstract interface

When an abstract interface is defined, add the ABSTRACT attribute to
subprogram symbols that define the interface body. Make use of that
when writing .mod files to include "abstract" on the interface statement.

Also, fix a problem with the order of symbols in a .mod file. Sometimes
a name is mentioned before the "real" declaration, e.g. in an access
statement. We want the order to be based on the real definitions. In
these cases we replace the symbol name with an identical name with a
different source location. Then by sorting based on the source location
we get symbols in the right order.

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

Added: 


Modified: 
flang/lib/Semantics/mod-file.cpp
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/modfile10.f90
flang/test/Semantics/procinterface01.f90
flang/test/Semantics/symbol15.f90

Removed: 




diff  --git a/flang/lib/Semantics/mod-file.cpp 
b/flang/lib/Semantics/mod-file.cpp
index 99ea65b753a6..f8e5889e4698 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -319,6 +319,10 @@ void ModFileWriter::PutSubprogram(const Symbol &symbol) {
 bindAttrs.set(Attr::BIND_C, true);
 attrs.set(Attr::BIND_C, false);
   }
+  bool isAbstract{attrs.test(Attr::ABSTRACT)};
+  if (isAbstract) {
+attrs.set(Attr::ABSTRACT, false);
+  }
   Attrs prefixAttrs{subprogramPrefixAttrs & attrs};
   // emit any non-prefix attributes in an attribute statement
   attrs &= ~subprogramPrefixAttrs;
@@ -331,7 +335,7 @@ void ModFileWriter::PutSubprogram(const Symbol &symbol) {
   bool isInterface{details.isInterface()};
   llvm::raw_ostream &os{isInterface ? decls_ : contains_};
   if (isInterface) {
-os << "interface\n";
+os << (isAbstract ? "abstract " : "") << "interface\n";
   }
   PutAttrs(os, prefixAttrs, std::nullopt, ""s, " "s);
   os << (details.isFunction() ? "function " : "subroutine ");
@@ -457,6 +461,11 @@ 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 x->name().begin() < y->name().begin();
+  });
   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 8d5284131cc0..73c624aefa22 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3085,11 +3085,14 @@ Symbol &SubprogramVisitor::PushSubprogramScope(
 symbol = &MakeSymbol(name, SubprogramDetails{});
   }
   symbol->set(subpFlag);
+  symbol->ReplaceName(name.source);
   PushScope(Scope::Kind::Subprogram, symbol);
   auto &details{symbol->get()};
   if (inInterfaceBlock()) {
 details.set_isInterface();
-if (!isAbstract()) {
+if (isAbstract()) {
+  symbol->attrs().set(Attr::ABSTRACT);
+} else {
   MakeExternal(*symbol);
 }
 if (isGeneric()) {

diff  --git a/flang/test/Semantics/modfile10.f90 
b/flang/test/Semantics/modfile10.f90
index ef10f1f23e8e..996178f5896d 100644
--- a/flang/test/Semantics/modfile10.f90
+++ b/flang/test/Semantics/modfile10.f90
@@ -90,3 +90,40 @@ subroutine test
 !  subroutine test()
 !  end
 !end
+
+! Ensure the type is emitted before its use
+module m2
+  private s
+  type :: t
+  contains
+procedure :: foo
+  end type
+  abstract interface
+subroutine s(x)
+  import
+  type(t) :: x
+end subroutine
+  end interface
+contains
+  subroutine foo(x)
+class(t) :: x
+  end subroutine
+end module
+!Expect: m2.mod
+!module m2
+!  type::t
+!  contains
+!procedure::foo
+!  end type
+!  private::s
+!  abstract interface
+!subroutine s(x)
+!  import::t
+!  type(t)::x
+!end
+!  end interface
+!contains
+!  subroutine foo(x)
+!class(t)::x
+!  end
+!end

diff  --git a/flang/test/Semantics/procinterface01.f90 
b/flang/test/Semantics/procinterface01.f90
index a960922d5637..dd9fd3b66041 100644
--- a/flang/test/Semantics/procinterface01.f90
+++ b/flang/test/Semantics/procinterface01.f90
@@ -5,7 +5,7 @@
 !DEF: /module1 Module
 module module1
  abstract interface
-  !DEF: /module1/abstract1 PUBLIC (Function) Subprogram REAL(4)
+  !DEF: /module1/abstract1 ABSTRACT, PUBLIC (Function) Subprogram REAL(4)
   !DEF: /module1/abstract1/x INTENT(IN) ObjectEntity REAL(4)
   real functi

[llvm-branch-commits] [flang] 1f525ec - [flang][NFC] Add GetTopLevelUnitContaining functions

2020-12-02 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-02T10:28:49-08:00
New Revision: 1f525ece4abfb6077d73e34acac0666855d19052

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

LOG: [flang][NFC] Add GetTopLevelUnitContaining functions

`GetTopLevelUnitContaining` returns the Scope nested in the global scope
that contains the given Scope or Symbol.

Use "Get" rather than "Find" in the name because "Find" implies it might
not be found, which can't happen. Following that logic, rename
`FindProgramUnitContaining` to `GetProgramUnitContaining` and have it
also return a reference rather that a pointer.

Note that the use of "ProgramUnit" is slightly confusing. In the Fortran
standard, "program-unit" refers to what is called a "TopLevelUnit" here.
What we are calling a "ProgramUnit" (here and in `ProgramTree`) includes
internal subprograms while "TopLevelUnit" does not.

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

Added: 


Modified: 
flang/include/flang/Semantics/tools.h
flang/lib/Semantics/check-return.cpp
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/tools.cpp

Removed: 




diff  --git a/flang/include/flang/Semantics/tools.h 
b/flang/include/flang/Semantics/tools.h
index 02faad4ecb2f..033c496c24b4 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -30,9 +30,14 @@ class DerivedTypeSpec;
 class Scope;
 class Symbol;
 
+// Note: Here ProgramUnit includes internal subprograms while TopLevelUnit
+// does not. "program-unit" in the Fortran standard matches TopLevelUnit.
+const Scope &GetTopLevelUnitContaining(const Scope &);
+const Scope &GetTopLevelUnitContaining(const Symbol &);
+const Scope &GetProgramUnitContaining(const Scope &);
+const Scope &GetProgramUnitContaining(const Symbol &);
+
 const Scope *FindModuleContaining(const Scope &);
-const Scope *FindProgramUnitContaining(const Scope &);
-const Scope *FindProgramUnitContaining(const Symbol &);
 const Scope *FindPureProcedureContaining(const Scope &);
 const Scope *FindPureProcedureContaining(const Symbol &);
 const Symbol *FindPointerComponent(const Scope &);

diff  --git a/flang/lib/Semantics/check-return.cpp 
b/flang/lib/Semantics/check-return.cpp
index 602ecc8a22f7..7830df034b55 100644
--- a/flang/lib/Semantics/check-return.cpp
+++ b/flang/lib/Semantics/check-return.cpp
@@ -16,11 +16,10 @@
 namespace Fortran::semantics {
 
 static const Scope *FindContainingSubprogram(const Scope &start) {
-  const Scope *scope{FindProgramUnitContaining(start)};
-  return scope &&
-  (scope->kind() == Scope::Kind::MainProgram ||
-  scope->kind() == Scope::Kind::Subprogram)
-  ? scope
+  const Scope &scope{GetProgramUnitContaining(start)};
+  return scope.kind() == Scope::Kind::MainProgram ||
+  scope.kind() == Scope::Kind::Subprogram
+  ? &scope
   : nullptr;
 }
 

diff  --git a/flang/lib/Semantics/resolve-names.cpp 
b/flang/lib/Semantics/resolve-names.cpp
index a879d009d12d..fd994b9d2827 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5602,11 +5602,11 @@ bool DeclarationVisitor::CheckForHostAssociatedImplicit(
 }
 
 bool DeclarationVisitor::IsUplevelReference(const Symbol &symbol) {
-  const Scope *symbolUnit{FindProgramUnitContaining(symbol)};
-  if (symbolUnit == FindProgramUnitContaining(currScope())) {
+  const Scope &symbolUnit{GetProgramUnitContaining(symbol)};
+  if (symbolUnit == GetProgramUnitContaining(currScope())) {
 return false;
   } else {
-Scope::Kind kind{DEREF(symbolUnit).kind()};
+Scope::Kind kind{symbolUnit.kind()};
 return kind == Scope::Kind::Subprogram || kind == Scope::Kind::MainProgram;
   }
 }

diff  --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 0ab2b376b3e2..b27c8b7cc867 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -37,13 +37,24 @@ static const Scope *FindScopeContaining(
   }
 }
 
+const Scope &GetTopLevelUnitContaining(const Scope &start) {
+  CHECK(!start.IsGlobal());
+  return DEREF(FindScopeContaining(
+  start, [](const Scope &scope) { return scope.parent().IsGlobal(); }));
+}
+
+const Scope &GetTopLevelUnitContaining(const Symbol &symbol) {
+  return GetTopLevelUnitContaining(symbol.owner());
+}
+
 const Scope *FindModuleContaining(const Scope &start) {
   return FindScopeContaining(
   start, [](const Scope &scope) { return scope.IsModule(); });
 }
 
-const Scope *FindProgramUnitContaining(const Scope &start) {
-  return FindScopeContaining(start, [](const Scope &scope) {
+const Scope &GetProgramUnitContaining(const Scope &start) {
+  CHECK(!start.IsGlobal());
+  return DEREF(FindScopeContaining(start, [](const Scope &scope) {
 switch (scope.kind()) {
 case Sc

[llvm-branch-commits] [flang] 86f59de - [flang] Fix bugs related to merging generics during USE

2020-12-02 Thread Tim Keith via llvm-branch-commits

Author: Tim Keith
Date: 2020-12-02T15:13:50-08:00
New Revision: 86f59de13b8058280d468984727bd1e6727f2112

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

LOG: [flang] Fix bugs related to merging generics during USE

When the same generic name is use-associated from two modules, the
generics are merged into a single one in the current scope. This change
fixes some bugs in that process.

When a generic is merged, it can have two specific procedures with the
same name as the generic (c.f. module m7c in modfile07.f90). We were
disallowing that by checking for duplicate names in the generic rather
than duplicate symbols. Changing `namesSeen` to `symbolsSeen` in
`ResolveSpecificsInGeneric` fixes that.

We weren't including each USE of those generics in the .mod file so in
some cases they were incorrect. Extend GenericDetails to specify all
use-associated symbols that are merged into the generic. This is used to
write out .mod files correctly.

The distinguishability check for specific procedures of a generic
sometimes have to refer to procedures from a use-associated generic in
error messages. In that case we don't have the source location of the
procedure so adapt the message to say where is was use-associated from.
This requires passing the scope through the checks to make that
determination.

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

Added: 


Modified: 
flang/include/flang/Semantics/symbol.h
flang/lib/Semantics/check-declarations.cpp
flang/lib/Semantics/mod-file.cpp
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/symbol.cpp
flang/test/Semantics/getsymbols03-a.f90
flang/test/Semantics/modfile07.f90
flang/test/Semantics/resolve17.f90

Removed: 




diff  --git a/flang/include/flang/Semantics/symbol.h 
b/flang/include/flang/Semantics/symbol.h
index 246bf2d0b338..833e3ab77720 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -155,6 +155,7 @@ class AssocEntityDetails : public EntityDetails {
   MaybeExpr expr_;
   std::optional rank_;
 };
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const AssocEntityDetails &);
 
 // An entity known to be an object.
 class ObjectEntityDetails : public EntityDetails {
@@ -432,6 +433,7 @@ class GenericDetails {
   const SymbolVector &specificProcs() const { return specificProcs_; }
   const std::vector &bindingNames() const { return bindingNames_; }
   void AddSpecificProc(const Symbol &, SourceName bindingName);
+  const SymbolVector &uses() const { return uses_; }
 
   // specific and derivedType indicate a specific procedure or derived type
   // with the same name as this generic. Only one of them may be set.
@@ -441,6 +443,7 @@ class GenericDetails {
   Symbol *derivedType() { return derivedType_; }
   const Symbol *derivedType() const { return derivedType_; }
   void set_derivedType(Symbol &derivedType);
+  void AddUse(const Symbol &);
 
   // Copy in specificProcs, specific, and derivedType from another generic
   void CopyFrom(const GenericDetails &);
@@ -450,22 +453,19 @@ class GenericDetails {
   const Symbol *CheckSpecific() const;
   Symbol *CheckSpecific();
 
-  const std::optional &useDetails() const { return useDetails_; }
-  void set_useDetails(const UseDetails &details) { useDetails_ = details; }
-
 private:
   GenericKind kind_;
   // all of the specific procedures for this generic
   SymbolVector specificProcs_;
   std::vector bindingNames_;
+  // Symbols used from other modules merged into this one
+  SymbolVector uses_;
   // a specific procedure with the same name as this generic, if any
   Symbol *specific_{nullptr};
   // a derived type with the same name as this generic, if any
   Symbol *derivedType_{nullptr};
-  // If two USEs of generics were merged to form this one, this is the
-  // UseDetails for one of them. Used for reporting USE errors.
-  std::optional useDetails_;
 };
+llvm::raw_ostream &operator<<(llvm::raw_ostream &, const GenericDetails &);
 
 class UnknownDetails {};
 

diff  --git a/flang/lib/Semantics/check-declarations.cpp 
b/flang/lib/Semantics/check-declarations.cpp
index a0b445b8d046..782e4c864421 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -120,11 +120,12 @@ class DistinguishabilityHelper {
 public:
   DistinguishabilityHelper(SemanticsContext &context) : context_{context} {}
   void Add(const Symbol &, GenericKind, const Symbol &, const Procedure &);
-  void Check();
+  void Check(const Scope &);
 
 private:
-  void SayNotDistinguishable(
-  const SourceName &, GenericKind, const Symbol &, const Symbol &);
+  void SayNotDistinguishable(const Scope &, const SourceName &, GenericKind,
+  const Symbol &, const Symbol &);
+  void A