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 @@ -644,7 +644,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 &); + Symbol &AddGenericUse(GenericDetails &, const SourceName &, const Symbol &); void AddAndCheckExplicitIntrinsicUse(SourceName, bool isIntrinsic); void ClearUseRenames() { useRenames_.clear(); } void ClearUseOnly() { useOnly_.clear(); } @@ -678,8 +678,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 DoAddUse(const SourceName &, const SourceName &, Symbol &localSymbol, - const Symbol &useSymbol); + void DoAddUse( + SourceName, SourceName, Symbol &localSymbol, const Symbol &useSymbol); void AddUse(const GenericSpecInfo &); // If appropriate, erase a previously USE-associated symbol void EraseRenamedSymbol(const Symbol &); @@ -2608,70 +2608,147 @@ } } -void ModuleVisitor::DoAddUse(const SourceName &location, - const SourceName &localName, Symbol &localSymbol, const Symbol &useSymbol) { +void ModuleVisitor::DoAddUse(SourceName location, SourceName localName, + Symbol &localSymbol, const Symbol &useSymbol) { if (localName != useSymbol.name()) { EraseRenamedSymbol(useSymbol); } - localSymbol.attrs() = useSymbol.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE}; - localSymbol.flags() = useSymbol.flags(); + if (auto *details{localSymbol.detailsIf()}) { + details->add_occurrence(location, *useModuleScope_); + return; + } + + if (localSymbol.has()) { + localSymbol.set_details(UseDetails{localName, useSymbol}); + localSymbol.attrs() = + useSymbol.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE}; + localSymbol.flags() = useSymbol.flags(); + return; + } + + Symbol &localUltimate{localSymbol.GetUltimate()}; const Symbol &useUltimate{useSymbol.GetUltimate()}; - if (auto *useDetails{localSymbol.detailsIf()}) { - const Symbol &localUltimate{localSymbol.GetUltimate()}; - if (localUltimate.owner() == useUltimate.owner()) { - // use-associating the same symbol again -- ok - } else if (localUltimate.has() && - useUltimate.has()) { - // use-associating generics with the same names: merge them into a - // new generic in this scope - auto generic1{localUltimate.get()}; - AddGenericUse(generic1, localName, useUltimate); - generic1.AddUse(localSymbol); - // useSymbol has specific g and so does generic1 - auto &generic2{useUltimate.get()}; - if (generic1.derivedType() && generic2.derivedType() && - generic1.derivedType() != generic2.derivedType()) { + if (&localUltimate == &useUltimate) { + // use-associating the same symbol again -- ok + return; + } + + auto checkAmbiguousDerivedType{[this, location, localName]( + const Symbol *t1, const Symbol *t2) { + if (!t1 || !t2) { + return true; + } else { + t1 = &t1->GetUltimate(); + t2 = &t2->GetUltimate(); + if (&t1 != &t2) { Say(location, - "Generic interface '%s' has ambiguous derived types" - " from modules '%s' and '%s'"_err_en_US, - localSymbol.name(), GetUsedModule(*useDetails).name(), - useUltimate.owner().GetName().value()); - context().SetError(localSymbol); + "Generic interface '%s' has ambiguous derived types from modules '%s' and '%s'"_err_en_US, + localName, t1->owner().GetName().value(), + t2->owner().GetName().value()); + return false; + } + } + }}; + + auto *localGeneric{localUltimate.detailsIf()}; + const auto *useGeneric{useUltimate.detailsIf()}; + auto combine{false}; + if (localGeneric) { + if (useGeneric) { + if (!checkAmbiguousDerivedType( + localGeneric->derivedType(), useGeneric->derivedType())) { + return; + } + combine = true; + } else if (useUltimate.has()) { + if (checkAmbiguousDerivedType( + &useUltimate, localGeneric->derivedType())) { + combine = true; } else { - generic1.CopyFrom(generic2); + return; } + } else if (&useUltimate == &BypassGeneric(localUltimate)) { + return; // nothing to do; used subprogram is local's specific + } + } else if (useGeneric) { + if (localUltimate.has()) { + if (checkAmbiguousDerivedType( + &localUltimate, useGeneric->derivedType())) { + combine = true; + } else { + return; + } + } else if (&localUltimate == &BypassGeneric(useUltimate).GetUltimate()) { + // Local is the specific of the used generic; replace it. EraseSymbol(localSymbol); - MakeSymbol(localSymbol.name(), localSymbol.attrs(), std::move(generic1)); - } else { + Symbol &newSymbol{MakeSymbol(localName, + useUltimate.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE}, + UseDetails{localName, useUltimate})}; + newSymbol.flags() = useSymbol.flags(); + return; + } + } + if (!combine) { + if (localSymbol.has() || localSymbol.has()) { ConvertToUseError(localSymbol, location, *useModuleScope_); + } else { + 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 if (auto *genericDetails{localSymbol.detailsIf()}) { - if (const auto *useDetails{useUltimate.detailsIf()}) { - AddGenericUse(*genericDetails, localName, useUltimate); - 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 { - genericDetails->CopyFrom(*useDetails); - } + return; + } + + // Two items are being use-associated from different modules + // to the same local name. At least one of them must be a generic, + // and the other one can be a generic or a derived type. + // (It could also have been the specific of the generic, but those + // cases are handled above without needing to make a local copy of the + // generic.) + + if (localGeneric) { + if (localSymbol.has()) { + // Create a local copy of a previously use-associated generic so that + // it can be locally extended without corrupting the original. + GenericDetails generic; + generic.CopyFrom(*localGeneric); + EraseSymbol(localSymbol); + Symbol &newSymbol{MakeSymbol( + localSymbol.name(), localSymbol.attrs(), std::move(generic))}; + newSymbol.flags() = localSymbol.flags(); + localGeneric = &newSymbol.get(); + localGeneric->AddUse(localSymbol); + } + if (useGeneric) { + // Combine two use-associated generics + localSymbol.attrs() = + useSymbol.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE}; + localSymbol.flags() = useSymbol.flags(); + AddGenericUse(*localGeneric, localName, useUltimate); + localGeneric->CopyFrom(*useGeneric); } else { - ConvertToUseError(localSymbol, location, *useModuleScope_); + CHECK(useUltimate.has()); + localGeneric->set_derivedType( + AddGenericUse(*localGeneric, localName, useUltimate)); } - } 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}); + CHECK(useGeneric && localUltimate.has()); + CHECK(localSymbol.has()); + // Create a local copy of the use-associated generic, then extend it + // with the local derived type. + GenericDetails generic; + generic.CopyFrom(*useGeneric); + EraseSymbol(localSymbol); + Symbol &newSymbol{MakeSymbol(localName, + useUltimate.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE}, + std::move(generic))}; + newSymbol.flags() = useUltimate.flags(); + auto &newUseGeneric{newSymbol.get()}; + AddGenericUse(newUseGeneric, localName, useUltimate); + newUseGeneric.AddUse(localSymbol); + newUseGeneric.set_derivedType(localSymbol); } } @@ -2684,9 +2761,12 @@ } // Create a UseDetails symbol for this USE and add it to generic -void ModuleVisitor::AddGenericUse( +Symbol &ModuleVisitor::AddGenericUse( GenericDetails &generic, const SourceName &name, const Symbol &useSymbol) { - generic.AddUse(currScope().MakeSymbol(name, {}, UseDetails{name, useSymbol})); + Symbol &newSymbol{ + currScope().MakeSymbol(name, {}, UseDetails{name, useSymbol})}; + generic.AddUse(newSymbol); + return newSymbol; } // Enforce C1406 @@ -5378,7 +5458,7 @@ symbol = &symbol->GetUltimate(); if (auto *details{symbol->detailsIf()}) { if (details->derivedType()) { - symbol = details->derivedType(); + symbol = &details->derivedType()->GetUltimate(); } } if (symbol->has()) { 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 @@ -211,7 +211,8 @@ for (std::size_t i{0}; i < from.specificProcs_.size(); ++i) { if (std::find_if(specificProcs_.begin(), specificProcs_.end(), [&](const Symbol &mySymbol) { - return &mySymbol == &*from.specificProcs_[i]; + return &mySymbol.GetUltimate() == + &from.specificProcs_[i]->GetUltimate(); }) == specificProcs_.end()) { specificProcs_.push_back(from.specificProcs_[i]); bindingNames_.push_back(from.bindingNames_[i]); 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 @@ -399,8 +399,8 @@ end !Expect: m7c.mod !module m7c -! use m7b, only: g => g_real ! use m7a, only: g => g_integer +! use m7b, only: g => g_real ! interface g ! procedure :: s ! end interface @@ -481,8 +481,8 @@ end !Expect: m8c.mod !module m8c -! use m8b, only: g ! use m8a, only: g +! use m8b, only: g ! interface g ! procedure :: s ! end interface @@ -579,8 +579,8 @@ end !Expect: m10c.mod !module m10c -! use m10b,only:operator(.ne.) ! use m10a,only:operator(.ne.) +! use m10b,only:operator(.ne.) ! interface operator(.ne.) ! end interface !end @@ -592,8 +592,8 @@ end !Expect: m10d.mod !module m10d -! use m10c,only:operator(.ne.) ! use m10a,only:operator(.ne.) +! use m10c,only:operator(.ne.) ! interface operator(.ne.) ! end interface ! private::operator(.ne.) 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 @@ -265,3 +265,104 @@ interface g end interface end module + +module m13a + contains + subroutine subr + end subroutine +end module +module m13b + use m13a + interface subr + module procedure subr + end interface +end module +module m13c + use m13a + use m13b + contains + subroutine test + call subr + end subroutine +end module +module m13d + use m13b + use m13a + contains + subroutine test + call subr + end subroutine +end module + +module m14a + type :: foo + integer :: n + end type +end module +module m14b + interface foo + module procedure bar + end interface + contains + real function bar(x) + real, intent(in) :: x + bar = x + end function +end module +module m14c + use m14a + use m14b + type(foo) :: x +end module +module m14d + use m14a + use m14b + type(foo) :: x + contains + subroutine test + real :: y + y = foo(1.0) + x = foo(2) + end subroutine +end module +module m14e + use m14b + use m14a + type(foo) :: x + contains + subroutine test + real :: y + y = foo(1.0) + x = foo(2) + end subroutine +end module + +module m15a + interface foo + module procedure bar + end interface + contains + subroutine bar + end subroutine +end module +module m15b + !ERROR: Cannot use-associate 'foo'; it is already declared in this scope + use m15a + contains + subroutine foo + end subroutine +end module +module m15c + contains + subroutine foo + end subroutine +end module +module m15d + use m15a + use m15c + contains + subroutine test + !ERROR: Reference to 'foo' is ambiguous + call foo + end subroutine +end module