Skip to content

Commit 2236048

Browse files
authored
[flang] Further refine errors vs warnings for ambiguous generics (#80161)
Ensure that the compiler emits a hard error for a generic interface with ambiguous specific procedures when it is declared as such, and the ambiguity doesn't involve optional or unlimited polymorphic dummy data arguments. But: emit an optional portability warning when the ambiguity in the generic interface is due to USE association's merging of multiple generics, as USE association may involve modules not under control of the programmer; we'll emit a hard error message if any the actual arguments in a particular reference to the generic procedure doesn't resolve to exactly one specific procedure. And don't emit warnings when potential ambiguity due to USE association is taking place in a module file; the warnings, if any, will have been produced when the module file was compiled.
1 parent be8b2d1 commit 2236048

File tree

2 files changed

+30
-16
lines changed

2 files changed

+30
-16
lines changed

flang/lib/Semantics/check-declarations.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class DistinguishabilityHelper {
192192

193193
private:
194194
void SayNotDistinguishable(const Scope &, const SourceName &, GenericKind,
195-
const Symbol &, const Symbol &, bool isError);
195+
const Symbol &, const Symbol &, bool isHardConflict);
196196
void AttachDeclaration(parser::Message &, const Scope &, const Symbol &);
197197

198198
SemanticsContext &context_;
@@ -3513,6 +3513,11 @@ void DistinguishabilityHelper::Add(const Symbol &generic, GenericKind kind,
35133513
}
35143514

35153515
void DistinguishabilityHelper::Check(const Scope &scope) {
3516+
if (FindModuleFileContaining(scope)) {
3517+
// Distinguishability was checked when the module was created;
3518+
// don't let optional warnings then become errors now.
3519+
return;
3520+
}
35163521
for (const auto &[name, info] : nameToSpecifics_) {
35173522
for (auto iter1{info.begin()}; iter1 != info.end(); ++iter1) {
35183523
const auto &[ultimate, procInfo]{*iter1};
@@ -3534,15 +3539,21 @@ void DistinguishabilityHelper::Check(const Scope &scope) {
35343539

35353540
void DistinguishabilityHelper::SayNotDistinguishable(const Scope &scope,
35363541
const SourceName &name, GenericKind kind, const Symbol &proc1,
3537-
const Symbol &proc2, bool isError) {
3538-
if (!isError &&
3539-
!context_.ShouldWarn(
3540-
common::LanguageFeature::IndistinguishableSpecifics)) {
3541-
// The rules for distinguishing specific procedures (F'2023 15.4.3.4.5)
3542-
// are inadequate for some real-world cases like pFUnit.
3543-
// When there are optional dummy arguments or unlimited polymorphic
3544-
// dummy data object arguments, the best that we can do is emit an optional
3545-
// portability warning.
3542+
const Symbol &proc2, bool isHardConflict) {
3543+
bool isUseAssociated{!scope.sourceRange().Contains(name)};
3544+
// The rules for distinguishing specific procedures (F'2023 15.4.3.4.5)
3545+
// are inadequate for some real-world cases like pFUnit.
3546+
// When there are optional dummy arguments or unlimited polymorphic
3547+
// dummy data object arguments, the best that we can do is emit an optional
3548+
// portability warning. Also, named generics created by USE association
3549+
// merging shouldn't receive hard errors for ambiguity.
3550+
// (Non-named generics might be defined I/O procedures or defined
3551+
// assignments that need to be used by the runtime.)
3552+
bool isWarning{!isHardConflict || (isUseAssociated && kind.IsName())};
3553+
if (isWarning &&
3554+
(!context_.ShouldWarn(
3555+
common::LanguageFeature::IndistinguishableSpecifics) ||
3556+
FindModuleFileContaining(scope))) {
35463557
return;
35473558
}
35483559
std::string name1{proc1.name().ToString()};
@@ -3557,17 +3568,20 @@ void DistinguishabilityHelper::SayNotDistinguishable(const Scope &scope,
35573568
}
35583569
}
35593570
parser::Message *msg;
3560-
if (scope.sourceRange().Contains(name)) {
3571+
if (!isUseAssociated) {
3572+
CHECK(isWarning == !isHardConflict);
35613573
msg = &context_.Say(name,
3562-
isError
3574+
isHardConflict
35633575
? "Generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
35643576
: "Generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US,
35653577
MakeOpName(name), name1, name2);
35663578
} else {
35673579
msg = &context_.Say(*GetTopLevelUnitContaining(proc1).GetName(),
3568-
isError
3569-
? "USE-associated generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US
3570-
: "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the incomplete rules in the standard"_port_en_US,
3580+
isHardConflict
3581+
? (isWarning
3582+
? "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_warn_en_US
3583+
: "USE-associated generic '%s' may not have specific procedures '%s' and '%s' as their interfaces are not distinguishable"_err_en_US)
3584+
: "USE-associated generic '%s' should not have specific procedures '%s' and '%s' as their interfaces are not distinguishable by the rules in the standard"_port_en_US,
35713585
MakeOpName(name), name1, name2);
35723586
}
35733587
AttachDeclaration(*msg, scope, proc1);

flang/test/Semantics/resolve17.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ subroutine g()
180180
end
181181
end module
182182
subroutine s9
183-
!ERROR: USE-associated generic 'g' may not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
183+
!PORTABILITY: USE-associated generic 'g' should not have specific procedures 'g' and 'g' as their interfaces are not distinguishable
184184
use m9a
185185
use m9b
186186
end

0 commit comments

Comments
 (0)