Skip to content

Commit 2b7a928

Browse files
authored
[flang] Improve USE merging of homonymous types, interfaces, and proc… (#79364)
…edures Fortran allows a generic interface to have the same name as a derived type in the same scope. It also allows a generic interface to have the same name as one of its specific procedures. When two modules define the same name, possibly more than once each, things get exciting. The standard is not clear, and other compilers do variously different things. We are currently emitting some errors prematurely for some usage in pfUnit due to how it combines two versions of a package together via USE association. This patch handles combinations of derived types and generic interfaces and their specific procedures in a more principled way. Errors due to ambiguity are deferred to actual usage of derived types and specific procedures -- and when they're not used, the program is unambiguous and no error issues.
1 parent 378c4d4 commit 2b7a928

File tree

9 files changed

+356
-197
lines changed

9 files changed

+356
-197
lines changed

flang/include/flang/Semantics/symbol.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,9 @@ class GenericDetails {
637637
const SymbolVector &uses() const { return uses_; }
638638

639639
// specific and derivedType indicate a specific procedure or derived type
640-
// with the same name as this generic. Only one of them may be set.
640+
// with the same name as this generic. Only one of them may be set in
641+
// a scope that declares them, but both can be set during USE association
642+
// when generics are combined.
641643
Symbol *specific() { return specific_; }
642644
const Symbol *specific() const { return specific_; }
643645
void set_specific(Symbol &specific);

flang/include/flang/Semantics/tools.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,5 +692,8 @@ std::string GetModuleOrSubmoduleName(const Symbol &);
692692
// Return the assembly name emitted for a common block.
693693
std::string GetCommonBlockObjectName(const Symbol &, bool underscoring);
694694

695+
// Check for ambiguous USE associations
696+
bool HadUseError(SemanticsContext &, SourceName at, const Symbol *);
697+
695698
} // namespace Fortran::semantics
696699
#endif // FORTRAN_SEMANTICS_TOOLS_H_

flang/lib/Semantics/expression.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
235235
return std::nullopt;
236236
} else if (MaybeExpr result{AsGenericExpr(std::move(ref))}) {
237237
return result;
238+
} else if (semantics::HadUseError(
239+
context_, GetContextualMessages().at(), &symbol)) {
240+
return std::nullopt;
238241
} else {
239242
if (!context_.HasError(last) && !context_.HasError(symbol)) {
240243
AttachDeclaration(

flang/lib/Semantics/resolve-names.cpp

Lines changed: 225 additions & 148 deletions
Large diffs are not rendered by default.

flang/lib/Semantics/symbol.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,10 @@ void GenericDetails::AddSpecificProc(
192192
}
193193
void GenericDetails::set_specific(Symbol &specific) {
194194
CHECK(!specific_);
195-
CHECK(!derivedType_);
196195
specific_ = &specific;
197196
}
198197
void GenericDetails::clear_specific() { specific_ = nullptr; }
199198
void GenericDetails::set_derivedType(Symbol &derivedType) {
200-
CHECK(!specific_);
201199
CHECK(!derivedType_);
202200
derivedType_ = &derivedType;
203201
}
@@ -211,7 +209,7 @@ const Symbol *GenericDetails::CheckSpecific() const {
211209
return const_cast<GenericDetails *>(this)->CheckSpecific();
212210
}
213211
Symbol *GenericDetails::CheckSpecific() {
214-
if (specific_) {
212+
if (specific_ && !specific_->has<UseErrorDetails>()) {
215213
for (const Symbol &proc : specificProcs_) {
216214
if (&proc == specific_) {
217215
return nullptr;

flang/lib/Semantics/tools.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,4 +1685,21 @@ std::string GetCommonBlockObjectName(const Symbol &common, bool underscoring) {
16851685
: common.name().ToString();
16861686
}
16871687

1688+
bool HadUseError(
1689+
SemanticsContext &context, SourceName at, const Symbol *symbol) {
1690+
if (const auto *details{
1691+
symbol ? symbol->detailsIf<UseErrorDetails>() : nullptr}) {
1692+
auto &msg{context.Say(
1693+
at, "Reference to '%s' is ambiguous"_err_en_US, symbol->name())};
1694+
for (const auto &[location, module] : details->occurrences()) {
1695+
msg.Attach(location, "'%s' was use-associated from module '%s'"_en_US, at,
1696+
module->GetName().value());
1697+
}
1698+
context.SetError(*symbol);
1699+
return true;
1700+
} else {
1701+
return false;
1702+
}
1703+
}
1704+
16881705
} // namespace Fortran::semantics

flang/test/Semantics/resolve17.f90

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -175,29 +175,14 @@ module m9b
175175
interface g
176176
module procedure g
177177
end interface
178-
contains
179-
subroutine g(x)
180-
real :: x
181-
end
182-
end module
183-
module m9c
184-
interface g
185-
module procedure g
186-
end interface
187178
contains
188179
subroutine g()
189180
end
190181
end module
191-
subroutine s9a
192-
use m9a
193-
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such interface and procedure are in scope
194-
use m9b
195-
end
196-
subroutine s9b
182+
subroutine s9
197183
!ERROR: USE-associated generic 'g' may not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
198184
use m9a
199-
!ERROR: Cannot use-associate generic interface 'g' with specific procedure of the same name when another such interface and procedure are in scope
200-
use m9c
185+
use m9b
201186
end
202187

203188
module m10a
@@ -223,24 +208,6 @@ subroutine s(x)
223208
end
224209
end
225210

226-
module m11a
227-
interface g
228-
end interface
229-
type g
230-
end type
231-
end module
232-
module m11b
233-
interface g
234-
end interface
235-
type g
236-
end type
237-
end module
238-
module m11c
239-
use m11a
240-
!ERROR: Generic interface 'g' has ambiguous derived types from modules 'm11a' and 'm11b'
241-
use m11b
242-
end module
243-
244211
module m12a
245212
interface ga
246213
module procedure sa

flang/test/Semantics/resolve18.f90

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,10 @@ function foo(x)
229229

230230
subroutine test15
231231
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
232+
use m15b ! ok
234233
end
235234

235+
236236
module m16a
237237
type foo
238238
integer j
@@ -259,18 +259,110 @@ function bar(x,y)
259259

260260
subroutine test16
261261
use m16a
262-
!ERROR: Generic interface 'foo' has ambiguous derived types from modules 'm16a' and 'm16b'
263-
use m16b
262+
use m16b ! ok
264263
end
265264

266265
subroutine test17
267266
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
267+
use m16a ! ok
270268
end
271269

272270
subroutine test18
273271
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
272+
use m15a ! ok
273+
end
274+
275+
module m21
276+
type foo
277+
integer a
278+
end type
279+
interface foo
280+
module procedure f1
281+
end interface
282+
contains
283+
function f1(a)
284+
f1 = a
285+
end
286+
end
287+
288+
module m22
289+
type foo
290+
real b
291+
end type
292+
interface foo
293+
module procedure f2
294+
end interface
295+
contains
296+
function f2(a,b)
297+
f2 = a + b
298+
end
299+
end
300+
301+
module m23
302+
interface foo
303+
module procedure foo
304+
module procedure f3
305+
end interface
306+
contains
307+
function foo()
308+
foo = 0.
309+
end
310+
function f3(a,b,c)
311+
f3 = a + b + c
312+
end
313+
end
314+
315+
module m24
316+
interface foo
317+
module procedure foo
318+
module procedure f4
319+
end interface
320+
contains
321+
function foo(a)
322+
foo = a
323+
end
324+
function f4(a,b,c,d)
325+
f4 = a + b + c +d
326+
end
327+
end
328+
329+
subroutine s_21_22_a
330+
use m21
331+
use m22
332+
print *, foo(1.) ! Intel error
333+
print *, foo(1.,2.) ! Intel error
334+
end
335+
336+
subroutine s_21_22_b
337+
use m21
338+
use m22
339+
!ERROR: 'foo' is not a derived type
340+
type(foo) x ! definite error: GNU and Intel catch
341+
end
342+
343+
subroutine s_21_23
344+
use m21
345+
use m23
346+
type(foo) x ! Intel and NAG error
347+
print *, foo(1.) ! Intel error
348+
print *, foo(1.,2.,3.) ! Intel error
349+
call ext(foo) ! GNU and Intel error
350+
end
351+
352+
subroutine s_22_23
353+
use m22
354+
use m23
355+
type(foo) x ! Intel and NAG error
356+
print *, foo(1.,2.) ! Intel error
357+
print *, foo(1.,2.,3.) ! Intel error
358+
call ext(foo) ! Intel error
359+
end
360+
361+
subroutine s_23_24
362+
use m23
363+
use m24
364+
print *, foo(1.,2.,3.) ! NAG error
365+
print *, foo(1.,2.,3.,4.) ! XLF error
366+
!ERROR: 'foo' is not a specific procedure
367+
call ext(foo) ! definite error
276368
end

flang/test/Semantics/symbol27.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ subroutine test1a
2828
!DEF: /test1a/foo (Function) Generic
2929
!DEF: /test1a/x ObjectEntity TYPE(foo)
3030
type(foo) :: x
31-
!DEF: /test1a/foo Use
31+
!REF: /m1a/foo
3232
!REF: /m1b/bar
3333
print *, foo(1), foo()
3434
end subroutine
@@ -41,7 +41,7 @@ subroutine test1b
4141
!DEF: /test1b/foo (Function) Generic
4242
!DEF: /test1b/x ObjectEntity TYPE(foo)
4343
type(foo) :: x
44-
!DEF: /test1b/foo Use
44+
!REF: /m1a/foo
4545
!REF: /m1b/bar
4646
print *, foo(1), foo()
4747
end subroutine

0 commit comments

Comments
 (0)