From 412f391ca4ba21f3d82df31ef4bb755d5d1e2909 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Sat, 17 Dec 2022 10:19:42 -0800 Subject: [PATCH] [flang] Check for another case of ambiguous generic resolution When specific procedures of a generic have dummy procedures, underspecified actual procedures can match more than one specific procedure. This can happen with actual procedures that are externals with implicit interfaces, including the completely unspecified case of a PROCEDURE() or EXTERNAL that doesn't even differentiate between a subroutine and a function. Generic resolution can already handle cases of ambiguous resolution due to the use of NULL() actual arguments with no MOLD= arguments to define their types. Extend the handling of ambiguous actual arguments to include the case of underspecified actual procedures. Differential Revision: https://reviews.llvm.org/D140151 --- flang/include/flang/Semantics/expression.h | 4 ++-- flang/lib/Semantics/expression.cpp | 23 +++++++++------------- flang/test/Semantics/resolve63.f90 | 20 ++++++++++++++++++- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/flang/include/flang/Semantics/expression.h b/flang/include/flang/Semantics/expression.h index cb38b65c71456..0dc1216bbeece 100644 --- a/flang/include/flang/Semantics/expression.h +++ b/flang/include/flang/Semantics/expression.h @@ -352,8 +352,8 @@ class ExpressionAnalyzer { 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 index 0d4156d621a44..a6fc90693aae3 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -2251,10 +2251,6 @@ std::pair ExpressionAnalyzer::ResolveGeneric( } } 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 @@ std::pair ExpressionAnalyzer::ResolveGeneric( // 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 @@ const Symbol &ExpressionAnalyzer::AccessSpecific( } 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 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name, } 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 ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name, 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 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name, 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 index a3154d82153a4..5c4d9c69cd85d 100644 --- a/flang/test/Semantics/resolve63.f90 +++ b/flang/test/Semantics/resolve63.f90 @@ -340,11 +340,29 @@ subroutine test 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