diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -155,6 +155,7 @@ 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 @@ 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 @@ 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 @@ 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 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -120,11 +120,12 @@ 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 AttachDeclaration(parser::Message &, const Scope &, const Symbol &); SemanticsContext &context_; struct ProcedureInfo { @@ -1020,7 +1021,7 @@ helper.Add(generic, kind, specific, *procedure); } } - helper.Check(); + helper.Check(generic.owner()); } static bool ConflictsWithIntrinsicAssignment(const Procedure &proc) { @@ -1637,7 +1638,7 @@ } } } - helper.Check(); + helper.Check(scope); } void SubprogramMatchHelper::Check( @@ -1859,7 +1860,7 @@ } } -void DistinguishabilityHelper::Check() { +void DistinguishabilityHelper::Check(const Scope &scope) { for (const auto &[name, info] : nameToInfo_) { auto count{info.size()}; for (std::size_t i1{0}; i1 < count - 1; ++i1) { @@ -1870,15 +1871,17 @@ ? evaluate::characteristics::Distinguishable : evaluate::characteristics::DistinguishableOpOrAssign}; if (!distinguishable(proc1, proc2)) { - SayNotDistinguishable(name, kind1, symbol1, symbol2); + SayNotDistinguishable( + GetTopLevelUnitContaining(scope), name, kind1, symbol1, symbol2); } } } } } -void DistinguishabilityHelper::SayNotDistinguishable(const SourceName &name, - GenericKind kind, const Symbol &proc1, const Symbol &proc2) { +void DistinguishabilityHelper::SayNotDistinguishable(const Scope &scope, + const SourceName &name, GenericKind kind, const Symbol &proc1, + const Symbol &proc2) { std::string name1{proc1.name().ToString()}; std::string name2{proc2.name().ToString()}; if (kind.IsOperator() || kind.IsAssignment()) { @@ -1890,12 +1893,34 @@ name2 = proc2.owner().GetName()->ToString() + '%' + name2; } } - auto &msg{context_.Say(name, - "Generic '%s' may not have specific procedures '%s' and '%s'" - " as their interfaces are not distinguishable"_err_en_US, - MakeOpName(name), name1, name2)}; - evaluate::AttachDeclaration(msg, proc1); - evaluate::AttachDeclaration(msg, proc2); + parser::Message *msg; + if (scope.sourceRange().Contains(name)) { + msg = &context_.Say(name, + "Generic '%s' may not have specific procedures '%s' and" + " '%s' as their interfaces are not distinguishable"_err_en_US, + MakeOpName(name), name1, name2); + } else { + msg = &context_.Say(*GetTopLevelUnitContaining(proc1).GetName(), + "USE-associated generic '%s' may not have specific procedures '%s' and" + " '%s' as their interfaces are not distinguishable"_err_en_US, + MakeOpName(name), name1, name2); + } + AttachDeclaration(*msg, scope, proc1); + AttachDeclaration(*msg, scope, proc2); +} + +// `evaluate::AttachDeclaration` doesn't handle the generic case where `proc` +// comes from a different module but is not necessarily use-associated. +void DistinguishabilityHelper::AttachDeclaration( + parser::Message &msg, const Scope &scope, const Symbol &proc) { + const Scope &unit{GetTopLevelUnitContaining(proc)}; + if (unit == scope) { + evaluate::AttachDeclaration(msg, proc); + } else { + msg.Attach(unit.GetName().value(), + "'%s' is USE-associated from module '%s'"_en_US, proc.name(), + unit.GetName().value()); + } } void CheckDeclarations(SemanticsContext &context) { diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -43,7 +43,7 @@ }; static std::optional GetSubmoduleParent(const parser::Program &); -static SymbolVector CollectSymbols(const Scope &); +static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &); static void PutEntity(llvm::raw_ostream &, const Symbol &); static void PutObjectEntity(llvm::raw_ostream &, const Symbol &); static void PutProcEntity(llvm::raw_ostream &, const Symbol &); @@ -178,12 +178,17 @@ // Put out the visible symbols from scope. bool ModFileWriter::PutSymbols(const Scope &scope) { - std::string buf; - llvm::raw_string_ostream typeBindings{ - buf}; // stuff after CONTAINS in derived type - for (const Symbol &symbol : CollectSymbols(scope)) { + SymbolVector sorted; + SymbolVector uses; + CollectSymbols(scope, sorted, uses); + std::string buf; // stuff after CONTAINS in derived type + llvm::raw_string_ostream typeBindings{buf}; + for (const Symbol &symbol : sorted) { PutSymbol(typeBindings, symbol); } + for (const Symbol &symbol : uses) { + PutUse(symbol); + } if (auto str{typeBindings.str()}; !str.empty()) { CHECK(scope.IsDerivedType()); decls_ << "contains\n" << str; @@ -393,10 +398,13 @@ } void ModFileWriter::PutGeneric(const Symbol &symbol) { + const auto &genericOwner{symbol.owner()}; auto &details{symbol.get()}; PutGenericName(decls_ << "interface ", symbol) << '\n'; for (const Symbol &specific : details.specificProcs()) { - decls_ << "procedure::" << specific.name() << '\n'; + if (specific.owner() == genericOwner) { + decls_ << "procedure::" << specific.name() << '\n'; + } } decls_ << "end interface\n"; if (symbol.attrs().test(Attr::PRIVATE)) { @@ -431,8 +439,8 @@ // Collect the symbols of this scope sorted by their original order, not name. // Namelists are an exception: they are sorted after other symbols. -SymbolVector CollectSymbols(const Scope &scope) { - SymbolVector sorted; +void CollectSymbols( + const Scope &scope, SymbolVector &sorted, SymbolVector &uses) { SymbolVector namelist; std::size_t commonSize{scope.commonBlocks().size()}; auto symbols{scope.GetSymbols()}; @@ -444,6 +452,9 @@ } else { sorted.push_back(symbol); } + if (const auto *details{symbol->detailsIf()}) { + uses.insert(uses.end(), details->uses().begin(), details->uses().end()); + } } } sorted.insert(sorted.end(), namelist.begin(), namelist.end()); @@ -451,7 +462,6 @@ sorted.push_back(*pair.second); } std::sort(sorted.end() - commonSize, sorted.end()); - return sorted; } void PutEntity(llvm::raw_ostream &os, const Symbol &symbol) { diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -623,6 +623,7 @@ void BeginModule(const parser::Name &, bool isSubmodule); bool BeginSubmodule(const parser::Name &, const parser::ParentIdentifier &); void ApplyDefaultAccess(); + void AddGenericUse(GenericDetails &, const SourceName &, const Symbol &); private: // The default access spec for this module. @@ -630,7 +631,7 @@ // The location of the last AccessStmt without access-ids, if any. std::optional prevAccessStmt_; // The scope of the module during a UseStmt - const Scope *useModuleScope_{nullptr}; + Scope *useModuleScope_{nullptr}; Symbol &SetAccess(const SourceName &, Attr attr, Symbol * = nullptr); // A rename in a USE statement: local => use @@ -641,7 +642,8 @@ // Record a use from useModuleScope_ of use Name/Symbol as local Name/Symbol SymbolRename AddUse(const SourceName &localName, const SourceName &useName); SymbolRename AddUse(const SourceName &, const SourceName &, Symbol *); - void AddUse(const SourceName &, Symbol &localSymbol, const Symbol &useSymbol); + void DoAddUse(const SourceName &, const SourceName &, Symbol &localSymbol, + const Symbol &useSymbol); void AddUse(const GenericSpecInfo &); Scope *FindModule(const parser::Name &, Scope *ancestor = nullptr); }; @@ -2300,8 +2302,14 @@ // Set useModuleScope_ to the Scope of the module being used. bool ModuleVisitor::Pre(const parser::UseStmt &x) { useModuleScope_ = FindModule(x.moduleName); - return useModuleScope_ != nullptr; + if (!useModuleScope_) { + return false; + } + // use the name from this source file + useModuleScope_->symbol()->ReplaceName(x.moduleName.source); + return true; } + void ModuleVisitor::Post(const parser::UseStmt &x) { if (const auto *list{std::get_if>(&x.u)}) { // Not a use-only: collect the names that were used in renames, @@ -2321,13 +2329,12 @@ for (const auto &[name, symbol] : *useModuleScope_) { if (symbol->attrs().test(Attr::PUBLIC) && !symbol->attrs().test(Attr::INTRINSIC) && - !symbol->detailsIf()) { - if (useNames.count(name) == 0) { - auto *localSymbol{FindInScope(currScope(), name)}; - if (!localSymbol) { - localSymbol = &CopySymbol(name, *symbol); - } - AddUse(x.moduleName.source, *localSymbol, *symbol); + !symbol->has() && useNames.count(name) == 0) { + SourceName location{x.moduleName.source}; + if (auto *localSymbol{FindInScope(currScope(), name)}) { + DoAddUse(location, localSymbol->name(), *localSymbol, *symbol); + } else { + DoAddUse(location, location, CopySymbol(name, *symbol), *symbol); } } } @@ -2356,7 +2363,7 @@ return {}; } auto &localSymbol{MakeSymbol(localName)}; - AddUse(useName, localSymbol, *useSymbol); + DoAddUse(useName, localName, localSymbol, *useSymbol); return {&localSymbol, useSymbol}; } @@ -2367,14 +2374,14 @@ const auto *useDetails{symbol.detailsIf()}; if (!useDetails) { auto &genericDetails{symbol.get()}; - useDetails = &genericDetails.useDetails().value(); + useDetails = &genericDetails.uses().at(0)->get(); } symbol.set_details( UseErrorDetails{*useDetails}.add_occurrence(location, module)); } -void ModuleVisitor::AddUse( - const SourceName &location, Symbol &localSymbol, const Symbol &useSymbol) { +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(); if (auto *useDetails{localSymbol.detailsIf()}) { @@ -2386,23 +2393,18 @@ // use-associating generics with the same names: merge them into a // new generic in this scope auto generic1{ultimate.get()}; - generic1.set_useDetails(*useDetails); + AddGenericUse(generic1, localName, useSymbol); + generic1.AddUse(localSymbol); // useSymbol has specific g and so does generic1 auto &generic2{useSymbol.get()}; - if (generic1.specific() && generic2.specific() && - generic1.specific() != generic2.specific()) { - Say(location, - "Generic interface '%s' has ambiguous specific procedures" - " from modules '%s' and '%s'"_err_en_US, - localSymbol.name(), GetUsedModule(*useDetails).name(), - useSymbol.owner().GetName().value()); - } else if (generic1.derivedType() && generic2.derivedType() && + 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()); + context().SetError(localSymbol); } else { generic1.CopyFrom(generic2); } @@ -2411,26 +2413,33 @@ } else { ConvertToUseError(localSymbol, location, *useModuleScope_); } - } else { - auto *genericDetails{localSymbol.detailsIf()}; - if (genericDetails && genericDetails->useDetails()) { - // localSymbol came from merging two use-associated generics - if (auto *useDetails{useSymbol.detailsIf()}) { - genericDetails->CopyFrom(*useDetails); + } else if (auto *genericDetails{localSymbol.detailsIf()}) { + if (const auto *useDetails{useSymbol.detailsIf()}) { + AddGenericUse(*genericDetails, localName, useSymbol); + if (genericDetails->derivedType() && useDetails->derivedType() && + genericDetails->derivedType() != useDetails->derivedType()) { + Say(location, + "Generic interface '%s' has ambiguous derived types" + " from modules '%s' and '%s'"_err_en_US, + localSymbol.name(), + genericDetails->derivedType()->owner().GetName().value(), + useDetails->derivedType()->owner().GetName().value()); } else { - ConvertToUseError(localSymbol, location, *useModuleScope_); + genericDetails->CopyFrom(*useDetails); } - } else if (auto *details{localSymbol.detailsIf()}) { - details->add_occurrence(location, *useModuleScope_); - } else if (!localSymbol.has()) { - Say(location, - "Cannot use-associate '%s'; it is already declared in this scope"_err_en_US, - localSymbol.name()) - .Attach(localSymbol.name(), "Previous declaration of '%s'"_en_US, - localSymbol.name()); } else { - localSymbol.set_details(UseDetails{location, useSymbol}); + ConvertToUseError(localSymbol, location, *useModuleScope_); } + } else if (auto *details{localSymbol.detailsIf()}) { + details->add_occurrence(location, *useModuleScope_); + } else if (!localSymbol.has()) { + Say(location, + "Cannot use-associate '%s'; it is already declared in this scope"_err_en_US, + localName) + .Attach(localSymbol.name(), "Previous declaration of '%s'"_en_US, + localName); + } else { + localSymbol.set_details(UseDetails{localName, useSymbol}); } } @@ -2443,6 +2452,12 @@ } } +// Create a UseDetails symbol for this USE and add it to generic +void ModuleVisitor::AddGenericUse( + GenericDetails &generic, const SourceName &name, const Symbol &useSymbol) { + generic.AddUse(currScope().MakeSymbol(name, {}, UseDetails{name, useSymbol})); +} + bool ModuleVisitor::BeginSubmodule( const parser::Name &name, const parser::ParentIdentifier &parentId) { auto &ancestorName{std::get(parentId.t)}; @@ -2574,9 +2589,9 @@ // this generic interface. Resolve those names to symbols. void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) { auto &details{generic.get()}; - std::set namesSeen; // to check for duplicate names + SymbolSet symbolsSeen; for (const Symbol &symbol : details.specificProcs()) { - namesSeen.insert(symbol.name()); + symbolsSeen.insert(symbol); } auto range{specificProcs_.equal_range(&generic)}; for (auto it{range.first}; it != range.second; ++it) { @@ -2613,7 +2628,7 @@ } } } - if (!namesSeen.insert(name->source).second) { + if (!symbolsSeen.insert(*symbol).second) { Say(name->source, "Procedure '%s' is already specified in generic '%s'"_err_en_US, name->source, MakeOpName(generic.name())); @@ -6127,7 +6142,10 @@ } Symbol &ultimate{existing->GetUltimate()}; if (auto *ultimateDetails{ultimate.detailsIf()}) { + // convert a use-associated generic into a local generic genericDetails.CopyFrom(*ultimateDetails); + AddGenericUse(genericDetails, existing->name(), + existing->get().symbol()); } else if (ultimate.has() || ultimate.has()) { genericDetails.set_specific(ultimate); diff --git a/flang/lib/Semantics/symbol.cpp b/flang/lib/Semantics/symbol.cpp --- a/flang/lib/Semantics/symbol.cpp +++ b/flang/lib/Semantics/symbol.cpp @@ -168,6 +168,10 @@ CHECK(!derivedType_); derivedType_ = &derivedType; } +void GenericDetails::AddUse(const Symbol &use) { + CHECK(use.has()); + uses_.push_back(use); +} const Symbol *GenericDetails::CheckSpecific() const { return const_cast(this)->CheckSpecific(); @@ -188,10 +192,7 @@ void GenericDetails::CopyFrom(const GenericDetails &from) { CHECK(specificProcs_.size() == bindingNames_.size()); CHECK(from.specificProcs_.size() == from.bindingNames_.size()); - if (from.specific_) { - CHECK(!specific_ || specific_ == from.specific_); - specific_ = from.specific_; - } + kind_ = from.kind_; if (from.derivedType_) { CHECK(!derivedType_ || derivedType_ == from.derivedType_); derivedType_ = from.derivedType_; @@ -257,9 +258,13 @@ return has() || has(); }, [&](const DerivedTypeDetails &) { - auto *derived{this->detailsIf()}; + const auto *derived{detailsIf()}; return derived && derived->isForwardReferenced(); }, + [&](const UseDetails &x) { + const auto *use{detailsIf()}; + return use && use->symbol() == x.symbol(); + }, [](const auto &) { return false; }, }, details); @@ -375,6 +380,26 @@ return os; } +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const GenericDetails &x) { + os << ' ' << x.kind().ToString(); + DumpBool(os, "(specific)", x.specific() != nullptr); + DumpBool(os, "(derivedType)", x.derivedType() != nullptr); + if (const auto &uses{x.uses()}; !uses.empty()) { + os << " (uses:"; + char sep{' '}; + for (const Symbol &use : uses) { + const Symbol &ultimate{use.GetUltimate()}; + os << sep << ultimate.name() << "->" + << ultimate.owner().GetName().value(); + sep = ','; + } + os << ')'; + } + os << " procs:"; + DumpSymbolVector(os, x.specificProcs()); + return os; +} + llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) { os << DetailsToString(details); std::visit( // @@ -411,13 +436,6 @@ } }, [](const HostAssocDetails &) {}, - [&](const GenericDetails &x) { - os << ' ' << x.kind().ToString(); - DumpBool(os, "(specific)", x.specific() != nullptr); - DumpBool(os, "(derivedType)", x.derivedType() != nullptr); - os << " procs:"; - DumpSymbolVector(os, x.specificProcs()); - }, [&](const ProcBindingDetails &x) { os << " => " << x.symbol().name(); DumpOptional(os, "passName", x.passName()); diff --git a/flang/test/Semantics/getsymbols03-a.f90 b/flang/test/Semantics/getsymbols03-a.f90 --- a/flang/test/Semantics/getsymbols03-a.f90 +++ b/flang/test/Semantics/getsymbols03-a.f90 @@ -10,5 +10,5 @@ ! RUN: %f18 -fget-symbols-sources -fparse-only %s 2>&1 | FileCheck %s ! CHECK:f:{{.*}}getsymbols03-b.f90, 2, 12-13 ! CHECK:main:{{.*}}getsymbols03-a.f90, 4, 9-13 -! CHECK:mm3:{{.*}}getsymbols03-b.f90, 1, 8-11 +! CHECK:mm3:{{.*}}getsymbols03-a.f90, 5, 6-9 ! CHECK:x:{{.*}}getsymbols03-a.f90, 6, 13-14 diff --git a/flang/test/Semantics/modfile07.f90 b/flang/test/Semantics/modfile07.f90 --- a/flang/test/Semantics/modfile07.f90 +++ b/flang/test/Semantics/modfile07.f90 @@ -332,3 +332,220 @@ !module m6b ! use m6a,only:operator(.lt.) !end + +module m7a + interface g_integer + module procedure s + end interface + private :: s +contains + subroutine s(x) + integer :: x + end +end +!Expect: m7a.mod +!module m7a +! interface g_integer +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! integer(4) :: x +! end +!end + +module m7b + interface g_real + module procedure s + end interface + private :: s +contains + subroutine s(x) + real :: x + end subroutine +end +!Expect: m7b.mod +!module m7b +! interface g_real +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! real(4) :: x +! end +!end + +module m7c + use m7a, only: g => g_integer + use m7b, only: g => g_real + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + complex :: x + end subroutine + subroutine test() + real :: x + integer :: y + complex :: z + call g(x) + call g(y) + call g(z) + end +end +!Expect: m7c.mod +!module m7c +! use m7b, only: g => g_real +! use m7a, only: g => g_integer +! interface g +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! complex(4) :: x +! end +! subroutine test() +! end +!end + +! Test m8 is like m7 but without renaming. + +module m8a + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + integer :: x + end +end +!Expect: m8a.mod +!module m8a +! interface g +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! integer(4) :: x +! end +!end + +module m8b + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + real :: x + end subroutine +end +!Expect: m8b.mod +!module m8b +! interface g +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! real(4) :: x +! end +!end + +module m8c + use m8a + use m8b + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + complex :: x + end subroutine + subroutine test() + real :: x + integer :: y + complex :: z + call g(x) + call g(y) + call g(z) + end +end +!Expect: m8c.mod +!module m8c +! use m8b, only: g +! use m8a, only: g +! interface g +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! complex(4) :: x +! end +! subroutine test() +! end +!end + +! Merging a use-associated generic with a local generic + +module m9a + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + integer :: x + end +end +!Expect: m9a.mod +!module m9a +! interface g +! procedure :: s +! end interface +! private :: s +!contains +! subroutine s(x) +! integer(4) :: x +! end +!end + +module m9b + use m9a + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + real :: x + end + subroutine test() + call g(1) + call g(1.0) + end +end +!Expect: m9b.mod +!module m9b +! use m9a,only:g +! interface g +! procedure::s +! end interface +! private::s +!contains +! subroutine s(x) +! real(4)::x +! end +! subroutine test() +! end +!end + diff --git a/flang/test/Semantics/resolve17.f90 b/flang/test/Semantics/resolve17.f90 --- a/flang/test/Semantics/resolve17.f90 +++ b/flang/test/Semantics/resolve17.f90 @@ -165,23 +165,18 @@ module m9a interface g - module procedure s1 module procedure g end interface contains subroutine g() end - subroutine s1(x) - integer :: x - end end module module m9b - use m9a interface g - module procedure s2 + module procedure g end interface contains - subroutine s2(x) + subroutine g(x) real :: x end end module @@ -190,18 +185,56 @@ module procedure g end interface contains - subroutine g(x) - real :: x + subroutine g() end end module -! Merge use-associated generics that have the same symbol (s1) -subroutine s9 +subroutine s9a use m9a use m9b end -! Merge use-associate generics each with specific of same name -subroutine s9c +subroutine s9b + !ERROR: USE-associated generic 'g' may not have specific procedures 'g' and 'g' as their interfaces are not distinguishable use m9a - !ERROR: Generic interface 'g' has ambiguous specific procedures from modules 'm9a' and 'm9c' use m9c end + +module m10a + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + integer :: x + end +end +module m10b + use m10a + !ERROR: Generic 'g' may not have specific procedures 's' and 's' as their interfaces are not distinguishable + interface g + module procedure s + end interface + private :: s +contains + subroutine s(x) + integer :: x + end +end + +module m11a + interface g + end interface + type g + end type +end module +module m11b + interface g + end interface + type g + end type +end module +module m11c + use m11a + !ERROR: Generic interface 'g' has ambiguous derived types from modules 'm11a' and 'm11b' + use m11b +end module