diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -352,8 +352,8 @@ using AdjustActuals = std::optional>; bool ResolveForward(const Symbol &); - std::pair - ResolveGeneric(const Symbol &, const ActualArguments &, const AdjustActuals &, + std::pair ResolveGeneric( + const Symbol &, const ActualArguments &, const AdjustActuals &, bool isSubroutine, bool mightBeStructureConstructor = false); void EmitGenericResolutionError( const Symbol &, bool dueToNullActuals, bool isSubroutine); diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2251,10 +2251,6 @@ } } if (const auto *details{ultimate.detailsIf()}) { - 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; @@ -2279,14 +2275,13 @@ // 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; } @@ -2363,9 +2358,9 @@ } 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 @@ -2401,7 +2396,7 @@ } const Symbol &ultimate{DEREF(symbol).GetUltimate()}; CheckForBadRecursion(name.source, ultimate); - bool dueToNullActual{false}; + bool dueToAmbiguity{false}; bool isGenericInterface{ultimate.has()}; bool isExplicitIntrinsic{ultimate.attrs().test(semantics::Attr::INTRINSIC)}; const Symbol *resolution{nullptr}; @@ -2410,7 +2405,7 @@ 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(resolution); @@ -2433,7 +2428,7 @@ std::move(specificCall->arguments)}; } else { if (isGenericInterface) { - EmitGenericResolutionError(*symbol, dueToNullActual, isSubroutine); + EmitGenericResolutionError(*symbol, dueToAmbiguity, isSubroutine); } return std::nullopt; } diff --git a/flang/test/Semantics/resolve63.f90 b/flang/test/Semantics/resolve63.f90 --- a/flang/test/Semantics/resolve63.f90 +++ b/flang/test/Semantics/resolve63.f90 @@ -340,11 +340,29 @@ 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