Skip to content

Commit 3d05ab6

Browse files
committed
[flang] Better error handling and testing of generics with homonymous specifics or derived types
Fortran allows a generic procedure interface to have the same name as a derived type in the same scope or the same name as one of its specific procedures. (It can't have both since a derived type and specific procedure can't have the same name in a scope.) Some popular compilers allow generic interfaces with distinct accessible homonymous specific procedures to be merged by USE association. Thsi compiler does not, and for good reason: it leads to ambiguity in cases where a procedure name appears outside a reference, such as in a PROCEDURE declaration statement as the procedure's interface, the target of a procedure pointer assignment statement, or as an actual argument. This patch cleans up the code that handles these cases, improves some error messages, and adds more tests. Resolves llvm#60228. Differential Revision: https://reviews.llvm.org/D150915
1 parent a8654b4 commit 3d05ab6

File tree

4 files changed

+191
-53
lines changed

4 files changed

+191
-53
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,15 @@ class ScopeHandler : public ImplicitRulesVisitor {
630630
// report the error elsewhere
631631
return *symbol;
632632
}
633-
SayAlreadyDeclared(name, *symbol);
633+
Symbol &errSym{*symbol};
634+
if (auto *d{symbol->detailsIf<GenericDetails>()}) {
635+
if (d->specific()) {
636+
errSym = *d->specific();
637+
} else if (d->derivedType()) {
638+
errSym = *d->derivedType();
639+
}
640+
}
641+
SayAlreadyDeclared(name, errSym);
634642
}
635643
// replace the old symbol with a new one with correct details
636644
EraseSymbol(*symbol);
@@ -2899,9 +2907,7 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
28992907

29002908
auto checkAmbiguousDerivedType{[this, location, localName](
29012909
const Symbol *t1, const Symbol *t2) {
2902-
if (!t1 || !t2) {
2903-
return true;
2904-
} else {
2910+
if (t1 && t2) {
29052911
t1 = &t1->GetUltimate();
29062912
t2 = &t2->GetUltimate();
29072913
if (&t1 != &t2) {
@@ -2912,36 +2918,26 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
29122918
return false;
29132919
}
29142920
}
2921+
return true;
29152922
}};
29162923

29172924
auto *localGeneric{localUltimate.detailsIf<GenericDetails>()};
29182925
const auto *useGeneric{useUltimate.detailsIf<GenericDetails>()};
29192926
auto combine{false};
29202927
if (localGeneric) {
29212928
if (useGeneric) {
2922-
if (!checkAmbiguousDerivedType(
2923-
localGeneric->derivedType(), useGeneric->derivedType())) {
2924-
return;
2925-
}
2926-
combine = true;
2929+
combine = checkAmbiguousDerivedType(
2930+
localGeneric->derivedType(), useGeneric->derivedType());
29272931
} else if (useUltimate.has<DerivedTypeDetails>()) {
2928-
if (checkAmbiguousDerivedType(
2929-
&useUltimate, localGeneric->derivedType())) {
2930-
combine = true;
2931-
} else {
2932-
return;
2933-
}
2932+
combine =
2933+
checkAmbiguousDerivedType(&useUltimate, localGeneric->derivedType());
29342934
} else if (&useUltimate == &BypassGeneric(localUltimate).GetUltimate()) {
29352935
return; // nothing to do; used subprogram is local's specific
29362936
}
29372937
} else if (useGeneric) {
29382938
if (localUltimate.has<DerivedTypeDetails>()) {
2939-
if (checkAmbiguousDerivedType(
2940-
&localUltimate, useGeneric->derivedType())) {
2941-
combine = true;
2942-
} else {
2943-
return;
2944-
}
2939+
combine =
2940+
checkAmbiguousDerivedType(&localUltimate, useGeneric->derivedType());
29452941
} else if (&localUltimate == &BypassGeneric(useUltimate).GetUltimate()) {
29462942
// Local is the specific of the used generic; replace it.
29472943
EraseSymbol(localSymbol);
@@ -2989,14 +2985,19 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
29892985
// cases are handled above without needing to make a local copy of the
29902986
// generic.)
29912987

2988+
std::optional<parser::MessageFixedText> msg;
29922989
if (localGeneric) {
29932990
if (localSymbol.has<UseDetails>()) {
29942991
// Create a local copy of a previously use-associated generic so that
29952992
// it can be locally extended without corrupting the original.
29962993
GenericDetails generic;
29972994
generic.CopyFrom(*localGeneric);
2998-
if (localGeneric->specific()) {
2999-
generic.set_specific(*localGeneric->specific());
2995+
if (Symbol * spec{localGeneric->specific()};
2996+
spec && !spec->attrs().test(Attr::PRIVATE)) {
2997+
generic.set_specific(*spec);
2998+
} else if (Symbol * dt{generic.derivedType()};
2999+
dt && dt->attrs().test(Attr::PRIVATE)) {
3000+
generic.clear_derivedType();
30003001
}
30013002
EraseSymbol(localSymbol);
30023003
Symbol &newSymbol{MakeSymbol(
@@ -3012,43 +3013,67 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30123013
localSymbol.flags() = useSymbol.flags();
30133014
AddGenericUse(*localGeneric, localName, useUltimate);
30143015
localGeneric->CopyFrom(*useGeneric);
3015-
if (useGeneric->specific()) {
3016-
if (!localGeneric->specific()) {
3017-
localGeneric->set_specific(
3018-
*const_cast<Symbol *>(useGeneric->specific()));
3016+
if (const Symbol * useSpec{useGeneric->specific()};
3017+
useSpec && !useSpec->attrs().test(Attr::PRIVATE)) {
3018+
if (localGeneric->derivedType()) {
3019+
msg =
3020+
"Cannot use-associate generic interface '%s' with specific procedure of the same name when another such interface and derived type are in scope"_err_en_US;
3021+
} else if (!localGeneric->specific()) {
3022+
localGeneric->set_specific(*const_cast<Symbol *>(useSpec));
30193023
} else if (&localGeneric->specific()->GetUltimate() !=
3020-
&useGeneric->specific()->GetUltimate()) {
3021-
Say(location,
3022-
"Cannot use-associate generic interface '%s' with specific procedure of the same name when another such generic is in scope"_err_en_US,
3023-
localName)
3024-
.Attach(
3025-
localSymbol.name(), "Previous USE of '%s'"_en_US, localName);
3024+
&useSpec->GetUltimate()) {
3025+
msg =
3026+
"Cannot use-associate generic interface '%s' with specific procedure of the same name when another such interface and procedure are in scope"_err_en_US;
3027+
}
3028+
} else if (const Symbol * useDT{useGeneric->derivedType()};
3029+
useDT && !useDT->attrs().test(Attr::PRIVATE)) {
3030+
if (localGeneric->specific()) {
3031+
msg =
3032+
"Cannot use-associate generic interface '%s' with derived type of the same name when another such interface and procedure are in scope"_err_en_US;
3033+
} else if (!localGeneric->derivedType()) {
3034+
localGeneric->set_derivedType(*const_cast<Symbol *>(useDT));
3035+
} else if (&localGeneric->derivedType()->GetUltimate() !=
3036+
&useDT->GetUltimate()) {
3037+
msg =
3038+
"Cannot use-associate generic interface '%s' with derived type of the same name when another such interface and derived type are in scope"_err_en_US;
30263039
}
30273040
}
30283041
} else {
30293042
CHECK(useUltimate.has<DerivedTypeDetails>());
3030-
localGeneric->set_derivedType(
3031-
AddGenericUse(*localGeneric, localName, useUltimate));
3043+
if (!localGeneric->derivedType()) {
3044+
localGeneric->set_derivedType(
3045+
AddGenericUse(*localGeneric, localName, useUltimate));
3046+
} else if (&localGeneric->derivedType()->GetUltimate() != &useUltimate) {
3047+
msg =
3048+
"Cannot use-associate derived type '%s' when a generic interface and derived type of the same name are in scope"_err_en_US;
3049+
}
30323050
}
30333051
} else {
30343052
CHECK(useGeneric && localUltimate.has<DerivedTypeDetails>());
30353053
CHECK(localSymbol.has<UseDetails>());
30363054
// Create a local copy of the use-associated generic, then extend it
30373055
// with the local derived type.
3038-
GenericDetails generic;
3039-
generic.CopyFrom(*useGeneric);
3040-
if (useGeneric->specific()) {
3041-
generic.set_specific(*const_cast<Symbol *>(useGeneric->specific()));
3042-
}
3043-
EraseSymbol(localSymbol);
3044-
Symbol &newSymbol{MakeSymbol(localName,
3045-
useUltimate.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE},
3046-
std::move(generic))};
3047-
newSymbol.flags() = useUltimate.flags();
3048-
auto &newUseGeneric{newSymbol.get<GenericDetails>()};
3049-
AddGenericUse(newUseGeneric, localName, useUltimate);
3050-
newUseGeneric.AddUse(localSymbol);
3051-
newUseGeneric.set_derivedType(localSymbol);
3056+
if (!useGeneric->derivedType() ||
3057+
&useGeneric->derivedType()->GetUltimate() == &localUltimate) {
3058+
GenericDetails generic;
3059+
generic.CopyFrom(*useGeneric);
3060+
EraseSymbol(localSymbol);
3061+
Symbol &newSymbol{MakeSymbol(localName,
3062+
useUltimate.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE},
3063+
std::move(generic))};
3064+
newSymbol.flags() = useUltimate.flags();
3065+
auto &newUseGeneric{newSymbol.get<GenericDetails>()};
3066+
AddGenericUse(newUseGeneric, localName, useUltimate);
3067+
newUseGeneric.AddUse(localSymbol);
3068+
newUseGeneric.set_derivedType(localSymbol);
3069+
} else if (useGeneric->derivedType()) {
3070+
msg =
3071+
"Cannot use-associate generic interface '%s' with derived type of the same name when another such derived type is in scope"_err_en_US;
3072+
}
3073+
}
3074+
if (msg) {
3075+
Say(location, std::move(*msg), localName)
3076+
.Attach(localSymbol.name(), "Previous USE of '%s'"_en_US, localName);
30523077
}
30533078
}
30543079

flang/test/Semantics/resolve17.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,13 +190,13 @@ subroutine g()
190190
end module
191191
subroutine s9a
192192
use m9a
193-
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such generic is in scope
193+
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such interface and procedure are in scope
194194
use m9b
195195
end
196196
subroutine s9b
197197
!ERROR: USE-associated generic 'g' may not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
198198
use m9a
199-
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such generic is in scope
199+
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such interface and procedure are in scope
200200
use m9c
201201
end
202202

flang/test/Semantics/resolve18.f90

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ function foo(x)
5555
module m4b
5656
type :: foo
5757
end type
58-
!ERROR: 'foo' is already declared in this scoping unit
5958
interface foo
6059
procedure :: foo
6160
end interface foo
6261
contains
62+
!ERROR: 'foo' is already declared in this scoping unit
6363
function foo(x)
6464
end
6565
end
@@ -125,12 +125,12 @@ end module m8
125125
module m9
126126
type f9
127127
end type f9
128-
!ERROR: 'f9' is already declared in this scoping unit
129128
interface f9
130129
real function f9()
131130
end function f9
132131
end interface f9
133132
contains
133+
!ERROR: 'f9' is already declared in this scoping unit
134134
function f9(x)
135135
end function f9
136136
end module m9
@@ -208,3 +208,69 @@ subroutine gen2(x)
208208
integer(4) :: x
209209
end subroutine gen2
210210
end module m15
211+
212+
module m15a
213+
interface foo
214+
module procedure foo
215+
end interface
216+
contains
217+
function foo()
218+
end
219+
end
220+
221+
module m15b
222+
interface foo
223+
module procedure foo
224+
end interface
225+
contains
226+
function foo(x)
227+
end
228+
end
229+
230+
subroutine test15
231+
use m15a
232+
!ERROR: Cannot use-associate generic interface 'foo' with specific procedure of the same name when another such interface and procedure are in scope
233+
use m15b
234+
end
235+
236+
module m16a
237+
type foo
238+
integer j
239+
end type
240+
interface foo
241+
module procedure bar
242+
end interface
243+
contains
244+
function bar(j)
245+
end
246+
end
247+
248+
module m16b
249+
type foo
250+
integer j, k
251+
end type
252+
interface foo
253+
module procedure bar
254+
end interface
255+
contains
256+
function bar(x,y)
257+
end
258+
end
259+
260+
subroutine test16
261+
use m16a
262+
!ERROR: Generic interface 'foo' has ambiguous derived types from modules 'm16a' and 'm16b'
263+
use m16b
264+
end
265+
266+
subroutine test17
267+
use m15a
268+
!ERROR: Cannot use-associate generic interface 'foo' with derived type of the same name when another such interface and procedure are in scope
269+
use m16a
270+
end
271+
272+
subroutine test18
273+
use m16a
274+
!ERROR: Cannot use-associate generic interface 'foo' with specific procedure of the same name when another such interface and derived type are in scope
275+
use m15a
276+
end

flang/test/Semantics/symbol27.f90

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
! RUN: %python %S/test_symbols.py %s %flang_fc1
2+
!DEF: /m1a Module
3+
module m1a
4+
!DEF: /m1a/foo PUBLIC DerivedType
5+
type :: foo
6+
!DEF: /m1a/foo/j ObjectEntity INTEGER(4)
7+
integer :: j
8+
end type
9+
end module
10+
!DEF: /m1b Module
11+
module m1b
12+
!DEF: /m1b/foo PUBLIC (Function) Generic
13+
interface foo
14+
!DEF: /m1b/bar PUBLIC (Function) Subprogram REAL(4)
15+
module procedure :: bar
16+
end interface
17+
contains
18+
!REF: /m1b/bar
19+
function bar()
20+
end function
21+
end module
22+
!DEF: /test1a (Subroutine) Subprogram
23+
subroutine test1a
24+
!REF: /m1a
25+
use :: m1a
26+
!REF: /m1b
27+
use :: m1b
28+
!DEF: /test1a/foo (Function) Generic
29+
!DEF: /test1a/x ObjectEntity TYPE(foo)
30+
type(foo) :: x
31+
!DEF: /test1a/foo Use
32+
!REF: /m1b/bar
33+
print *, foo(1), foo()
34+
end subroutine
35+
!DEF: /test1b (Subroutine) Subprogram
36+
subroutine test1b
37+
!REF: /m1b
38+
use :: m1b
39+
!REF: /m1a
40+
use :: m1a
41+
!DEF: /test1b/foo (Function) Generic
42+
!DEF: /test1b/x ObjectEntity TYPE(foo)
43+
type(foo) :: x
44+
!DEF: /test1b/foo Use
45+
!REF: /m1b/bar
46+
print *, foo(1), foo()
47+
end subroutine

0 commit comments

Comments
 (0)