Skip to content

Commit a43fa72

Browse files
committed
[flang] More information on generic resolution failures
When a generic procedure reference does not match any of its specific procedures, run through them and emit the errors for each attempted match, so that the user has more information to resolve the problem by adjusting the actual arguments.
1 parent f607b2a commit a43fa72

File tree

7 files changed

+80
-23
lines changed

7 files changed

+80
-23
lines changed

flang/include/flang/Evaluate/call.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class ActualArgument {
112112
int Rank() const;
113113
bool operator==(const ActualArgument &) const;
114114
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
115+
std::string AsFortran() const;
115116

116117
std::optional<parser::CharBlock> keyword() const { return keyword_; }
117118
ActualArgument &set_keyword(parser::CharBlock x) {

flang/include/flang/Semantics/expression.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ class ExpressionAnalyzer {
370370
std::pair<const Symbol *, bool /* failure due ambiguity */> ResolveGeneric(
371371
const Symbol &, const ActualArguments &, const AdjustActuals &,
372372
bool isSubroutine, bool mightBeStructureConstructor = false);
373-
void EmitGenericResolutionError(
374-
const Symbol &, bool dueToNullActuals, bool isSubroutine);
373+
void EmitGenericResolutionError(const Symbol &, bool dueToNullActuals,
374+
bool isSubroutine, ActualArguments &);
375375
const Symbol &AccessSpecific(
376376
const Symbol &originalGeneric, const Symbol &specific);
377377
std::optional<CalleeAndArguments> GetCalleeAndArguments(const parser::Name &,

flang/lib/Evaluate/formatting.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ llvm::raw_ostream &ActualArgument::AsFortran(llvm::raw_ostream &o) const {
252252
return o;
253253
}
254254

255+
std::string ActualArgument::AsFortran() const {
256+
std::string result;
257+
llvm::raw_string_ostream sstream(result);
258+
AsFortran(sstream);
259+
return result;
260+
}
261+
255262
llvm::raw_ostream &SpecificIntrinsic::AsFortran(llvm::raw_ostream &o) const {
256263
return o << name;
257264
}

flang/lib/Semantics/check-call.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,10 +2241,9 @@ static void CheckSpecificIntrinsic(const characteristics::Procedure &proc,
22412241
}
22422242
}
22432243

2244-
static parser::Messages CheckExplicitInterface(
2245-
const characteristics::Procedure &proc, evaluate::ActualArguments &actuals,
2246-
SemanticsContext &context, const Scope *scope,
2247-
const evaluate::SpecificIntrinsic *intrinsic,
2244+
parser::Messages CheckExplicitInterface(const characteristics::Procedure &proc,
2245+
evaluate::ActualArguments &actuals, SemanticsContext &context,
2246+
const Scope *scope, const evaluate::SpecificIntrinsic *intrinsic,
22482247
bool allowActualArgumentConversions, bool extentErrors,
22492248
bool ignoreImplicitVsExplicit) {
22502249
evaluate::FoldingContext &foldingContext{context.foldingContext()};

flang/lib/Semantics/check-call.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@
1212
#define FORTRAN_SEMANTICS_CHECK_CALL_H_
1313

1414
#include "flang/Evaluate/call.h"
15+
#include "flang/Parser/message.h"
1516

16-
namespace Fortran::parser {
17-
class Messages;
18-
class ContextualMessages;
19-
} // namespace Fortran::parser
2017
namespace Fortran::evaluate::characteristics {
2118
struct Procedure;
2219
}
@@ -47,6 +44,12 @@ bool CheckArgumentIsConstantExprInRange(
4744
const evaluate::ActualArguments &actuals, int index, int lowerBound,
4845
int upperBound, parser::ContextualMessages &messages);
4946

47+
parser::Messages CheckExplicitInterface(
48+
const evaluate::characteristics::Procedure &, evaluate::ActualArguments &,
49+
SemanticsContext &, const Scope *, const evaluate::SpecificIntrinsic *,
50+
bool allowActualArgumentConversions, bool extentErrors,
51+
bool ignoreImplicitVsExplicit);
52+
5053
// Checks actual arguments for the purpose of resolving a generic interface.
5154
bool CheckInterfaceForGeneric(const evaluate::characteristics::Procedure &,
5255
evaluate::ActualArguments &, SemanticsContext &,

flang/lib/Semantics/expression.cpp

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,7 +2556,8 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
25562556
ResolveGeneric(generic, arguments, adjustment, isSubroutine)};
25572557
sym = pair.first;
25582558
if (!sym) {
2559-
EmitGenericResolutionError(generic, pair.second, isSubroutine);
2559+
EmitGenericResolutionError(
2560+
generic, pair.second, isSubroutine, arguments);
25602561
return std::nullopt;
25612562
}
25622563
// re-resolve the name to the specific binding
@@ -3098,16 +3099,39 @@ const Symbol &ExpressionAnalyzer::AccessSpecific(
30983099
}
30993100
}
31003101

3101-
void ExpressionAnalyzer::EmitGenericResolutionError(
3102-
const Symbol &symbol, bool dueToAmbiguity, bool isSubroutine) {
3103-
Say(dueToAmbiguity
3104-
? "The 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
3105-
: semantics::IsGenericDefinedOp(symbol)
3106-
? "No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US
3107-
: isSubroutine
3108-
? "No specific subroutine of generic '%s' matches the actual arguments"_err_en_US
3109-
: "No specific function of generic '%s' matches the actual arguments"_err_en_US,
3110-
symbol.name());
3102+
void ExpressionAnalyzer::EmitGenericResolutionError(const Symbol &symbol,
3103+
bool dueToAmbiguity, bool isSubroutine, ActualArguments &arguments) {
3104+
if (auto *msg{Say(dueToAmbiguity
3105+
? "The 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
3106+
: semantics::IsGenericDefinedOp(symbol)
3107+
? "No specific procedure of generic operator '%s' matches the actual arguments"_err_en_US
3108+
: isSubroutine
3109+
? "No specific subroutine of generic '%s' matches the actual arguments"_err_en_US
3110+
: "No specific function of generic '%s' matches the actual arguments"_err_en_US,
3111+
symbol.name())}) {
3112+
if (const auto *generic{
3113+
symbol.GetUltimate().detailsIf<semantics::GenericDetails>()}) {
3114+
parser::ContextualMessages &messages{GetContextualMessages()};
3115+
semantics::Scope &scope{context_.FindScope(messages.at())};
3116+
for (const Symbol &specific : generic->specificProcs()) {
3117+
if (auto procChars{characteristics::Procedure::Characterize(
3118+
specific, GetFoldingContext())}) {
3119+
if (auto reasons{semantics::CheckExplicitInterface(*procChars,
3120+
arguments, context_, &scope, /*intrinsic=*/nullptr,
3121+
/*allocActualARgumentConversions=*/false,
3122+
/*extentErrors=*/false,
3123+
/*ignoreImplicitVsExplicit=*/false)};
3124+
!reasons.empty()) {
3125+
reasons.AttachTo(
3126+
msg->Attach(specific.name(),
3127+
"Specific procedure '%s' does not match the actual arguments"_en_US,
3128+
specific.name()),
3129+
parser::Severity::None);
3130+
}
3131+
}
3132+
}
3133+
}
3134+
}
31113135
}
31123136

31133137
auto ExpressionAnalyzer::GetCalleeAndArguments(
@@ -3182,7 +3206,8 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
31823206
std::move(specificCall->arguments)};
31833207
} else {
31843208
if (isGenericInterface) {
3185-
EmitGenericResolutionError(*symbol, dueToAmbiguity, isSubroutine);
3209+
EmitGenericResolutionError(
3210+
*symbol, dueToAmbiguity, isSubroutine, arguments);
31863211
}
31873212
return std::nullopt;
31883213
}
@@ -5115,7 +5140,8 @@ const Symbol *ArgumentAnalyzer::FindBoundOp(parser::CharBlock oprName,
51155140
if (isAmbiguous) {
51165141
*isAmbiguous = pair.second;
51175142
}
5118-
context_.EmitGenericResolutionError(*generic, pair.second, isSubroutine);
5143+
context_.EmitGenericResolutionError(
5144+
*generic, pair.second, isSubroutine, actuals_);
51195145
}
51205146
}
51215147
return nullptr;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck %s
2+
module m
3+
interface generic
4+
procedure :: sub1, sub2
5+
end interface
6+
contains
7+
subroutine sub1(x)
8+
end
9+
subroutine sub2(j)
10+
end
11+
end
12+
13+
program test
14+
use m
15+
!CHECK: error: No specific subroutine of generic 'generic' matches the actual arguments
16+
!CHECK: Specific procedure 'sub1' does not match the actual arguments
17+
!CHECK: Actual argument type 'REAL(8)' is not compatible with dummy argument type 'REAL(4)'
18+
!CHECK: Specific procedure 'sub2' does not match the actual arguments
19+
!CHECK: Actual argument type 'REAL(8)' is not compatible with dummy argument type 'INTEGER(4)'
20+
call generic(1.d0)
21+
end

0 commit comments

Comments
 (0)