using AdjustActuals =
std::optional<std::function<bool(const Symbol &, ActualArguments &)>>;
bool ResolveForward(const Symbol &);
- std::pair<const Symbol *, bool /* failure due to NULL() actuals */>
- ResolveGeneric(const Symbol &, const ActualArguments &, const AdjustActuals &,
+ std::pair<const Symbol *, bool /* failure due ambiguity */> ResolveGeneric(
+ const Symbol &, const ActualArguments &, const AdjustActuals &,
bool isSubroutine, bool mightBeStructureConstructor = false);
void EmitGenericResolutionError(
const Symbol &, bool dueToNullActuals, bool isSubroutine);
}
}
if (const auto *details{ultimate.detailsIf<semantics::GenericDetails>()}) {
- bool anyBareNullActual{
- std::find_if(actuals.begin(), actuals.end(), [](auto iter) {
- return IsBareNullPointer(iter->UnwrapExpr());
- }) != actuals.end()};
for (const Symbol &specific : details->specificProcs()) {
if (isSubroutine != !IsFunction(specific)) {
continue;
// 16.9.144(6): a bare NULL() is not allowed as an actual
// argument to a generic procedure if the specific procedure
// cannot be unambiguously distinguished
- return {nullptr, true /* due to NULL actuals */};
+ // Underspecified external procedure actual arguments can
+ // also lead to ambiguity.
+ return {nullptr, true /* due to ambiguity */};
}
if (!procedure->IsElemental()) {
// takes priority over elemental match
nonElemental = &specific;
- if (!anyBareNullActual) {
- break; // unambiguous case
- }
} else {
elemental = &specific;
}
}
void ExpressionAnalyzer::EmitGenericResolutionError(
- const Symbol &symbol, bool dueToNullActuals, bool isSubroutine) {
- Say(dueToNullActuals
- ? "One or more NULL() actual arguments to the generic procedure '%s' requires a MOLD= for disambiguation"_err_en_US
+ const Symbol &symbol, bool dueToAmbiguity, bool isSubroutine) {
+ Say(dueToAmbiguity
+ ? "One or more actual arguments to the generic procedure '%s' matched multiple specific procedures, perhaps due to use of NULL() without MOLD= or an actual procedure with an implicit interface"_err_en_US
: semantics::IsGenericDefinedOp(symbol)
? "No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US
: isSubroutine
}
const Symbol &ultimate{DEREF(symbol).GetUltimate()};
CheckForBadRecursion(name.source, ultimate);
- bool dueToNullActual{false};
+ bool dueToAmbiguity{false};
bool isGenericInterface{ultimate.has<semantics::GenericDetails>()};
bool isExplicitIntrinsic{ultimate.attrs().test(semantics::Attr::INTRINSIC)};
const Symbol *resolution{nullptr};
auto pair{ResolveGeneric(*symbol, arguments, noAdjustment, isSubroutine,
mightBeStructureConstructor)};
resolution = pair.first;
- dueToNullActual = pair.second;
+ dueToAmbiguity = pair.second;
if (resolution) {
// re-resolve name to the specific procedure
name.symbol = const_cast<Symbol *>(resolution);
std::move(specificCall->arguments)};
} else {
if (isGenericInterface) {
- EmitGenericResolutionError(*symbol, dueToNullActual, isSubroutine);
+ EmitGenericResolutionError(*symbol, dueToAmbiguity, isSubroutine);
}
return std::nullopt;
}
call generic(null(), ip) ! ok
call generic(null(mold=ip), null()) ! ok
call generic(null(), null(mold=ip)) ! ok
- !ERROR: One or more NULL() actual arguments to the generic procedure 'generic' requires a MOLD= for disambiguation
+ !ERROR: One or more actual arguments to the generic procedure 'generic' matched multiple specific procedures, perhaps due to use of NULL() without MOLD= or an actual procedure with an implicit interface
call generic(null(), null())
end subroutine
end
+module m9
+ interface generic
+ procedure s1, s2
+ end interface
+ contains
+ subroutine s1(jf)
+ procedure(integer) :: jf
+ end subroutine
+ subroutine s2(af)
+ procedure(real) :: af
+ end subroutine
+ subroutine test
+ external underspecified
+ !ERROR: One or more actual arguments to the generic procedure 'generic' matched multiple specific procedures, perhaps due to use of NULL() without MOLD= or an actual procedure with an implicit interface
+ call generic(underspecified)
+ end subroutine
+end module
+
! Ensure no bogus errors for assignments to CLASS(*) allocatable
module m10
type :: t1