[flang] Clarify edge case of host association and generic interfaces

Name resolution was mishandling cases of generic interfaces and specific procedures
(sometimes complicatd by use of the same name for each) when the specific procedure
was accessed by means of host association; only the scope of the generic interface
definition was searched for the specific procedure.  Also search enclosing scopes
in the usual way.

Differential Revision: https://reviews.llvm.org/D135213
This commit is contained in:
Peter Klausler 2022-10-04 12:11:20 -07:00
parent eb04f321c3
commit b7a0482a0a
2 changed files with 48 additions and 20 deletions

View File

@ -7233,8 +7233,8 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
Symbol *existing{nullptr};
// Check all variants of names, e.g. "operator(.ne.)" for "operator(/=)"
for (const std::string &n : GetAllNames(context(), symbolName)) {
if (auto iter{currScope().find(n)}; iter != currScope().end()) {
existing = &*iter->second;
existing = currScope().FindSymbol(SourceName{n});
if (existing) {
break;
}
}
@ -7249,24 +7249,28 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
genericDetails.set_specific(*existingGeneric->specific());
}
AddGenericUse(genericDetails, existing->name(), existingUse->symbol());
} else if (existing == &ultimate) {
// Extending an extant generic in the same scope
info.Resolve(existing);
return;
} else {
// Host association of a generic is handled in ResolveGeneric()
CHECK(existing->has<HostAssocDetails>());
} else if (&existing->owner() == &currScope()) {
if (existing == &ultimate) {
// Extending an extant generic in the same scope
info.Resolve(existing);
return;
} else {
// Host association of a generic is handled elsewhere
CHECK(existing->has<HostAssocDetails>());
}
}
} else if (ultimate.has<SubprogramDetails>() ||
ultimate.has<SubprogramNameDetails>()) {
genericDetails.set_specific(*existing);
} else if (ultimate.has<DerivedTypeDetails>()) {
genericDetails.set_derivedType(*existing);
} else {
} else if (&existing->owner() == &currScope()) {
SayAlreadyDeclared(symbolName, *existing);
return;
}
EraseSymbol(*existing);
if (&existing->owner() == &currScope()) {
EraseSymbol(*existing);
}
}
info.Resolve(&MakeSymbol(symbolName, Attrs{}, std::move(genericDetails)));
}

View File

@ -61,24 +61,48 @@ contains
end subroutine
subroutine test3
interface abs
module procedure abs_int_redef2 ! override module's use of m1
module procedure abs_complex_redef ! extend module's use of m1
end interface
!CHECK: abs_int_redef2(
!CHECK: abs_int_redef(
print *, abs(1)
!CHECK: 1._4
print *, abs(1.)
!CHECK: 1.41421353816986083984375_4
!CHECK: abs_complex_redef(
print *, abs((1,1))
!CHECK: abs_noargs(
print *, abs()
block
use m1, only: abs ! override the override
!CHECK: abs_int_redef(
print *, abs(1)
intrinsic abs ! override the extension
!CHECK: 1.41421353816986083984375_4
print *, abs((1,1))
end block
end subroutine
integer function abs_int_redef2(j)
integer, intent(in) :: j
abs_int_redef2 = j
real function abs_complex_redef(z)
complex, intent(in) :: z
abs_complex_redef = z
end function
subroutine test4
!CHECK: abs(
print *, abs(1)
contains
integer function abs(n) ! override module's use of m1
integer, intent(in) :: n
abs = n
end function
end subroutine
end module
module m4
contains
integer function abs(n)
integer, intent(in) :: n
abs = n
end function
subroutine test5
interface abs
module procedure abs ! same name, host-associated
end interface
!CHECK: abs(
print *, abs(1)
end subroutine
end module