Skip to content

Commit bdbebef

Browse files
committed
[flang] Warn about inconsistent implicit interfaces
When a global procedure has no explicit interface, emit warnings when its references are inconsistent implicit procedure interfaces. Differential Revision: https://reviews.llvm.org/D145097
1 parent ff65a58 commit bdbebef

File tree

7 files changed

+102
-6
lines changed

7 files changed

+102
-6
lines changed

flang/include/flang/Evaluate/characteristics.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ struct DummyArgument {
259259
bool operator!=(const DummyArgument &that) const { return !(*this == that); }
260260
static std::optional<DummyArgument> FromActual(
261261
std::string &&, const Expr<SomeType> &, FoldingContext &);
262+
static std::optional<DummyArgument> FromActual(
263+
std::string &&, const ActualArgument &, FoldingContext &);
262264
bool IsOptional() const;
263265
void SetOptional(bool = true);
264266
common::Intent GetIntent() const;
@@ -338,6 +340,10 @@ struct Procedure {
338340
const ProcedureDesignator &, FoldingContext &);
339341
static std::optional<Procedure> Characterize(
340342
const ProcedureRef &, FoldingContext &);
343+
// Characterizes the procedure being referenced, deducing dummy argument
344+
// types from actual arguments in the case of an implicit interface.
345+
static std::optional<Procedure> FromActuals(
346+
const ProcedureDesignator &, const ActualArguments &, FoldingContext &);
341347

342348
// At most one of these will return true.
343349
// For "EXTERNAL P" with no type for or calls to P, both will be false.

flang/include/flang/Semantics/expression.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ class ExpressionAnalyzer {
386386
semantics::SemanticsContext &context_;
387387
FoldingContext &foldingContext_{context_.foldingContext()};
388388
std::map<parser::CharBlock, int> impliedDos_; // values are INTEGER kinds
389+
std::map<parser::CharBlock,
390+
std::pair<parser::CharBlock, evaluate::characteristics::Procedure>>
391+
implicitInterfaces_;
389392
bool isWholeAssumedSizeArrayOk_{false};
390393
bool isNullPointerOk_{false};
391394
bool useSavedTypedExprs_{true};

flang/lib/Evaluate/characteristics.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,17 @@ std::optional<DummyArgument> DummyArgument::FromActual(
724724
expr.u);
725725
}
726726

727+
std::optional<DummyArgument> DummyArgument::FromActual(
728+
std::string &&name, const ActualArgument &arg, FoldingContext &context) {
729+
if (const auto *expr{arg.UnwrapExpr()}) {
730+
return FromActual(std::move(name), *expr, context);
731+
} else if (arg.GetAssumedTypeDummy()) {
732+
return std::nullopt;
733+
} else {
734+
return DummyArgument{AlternateReturn{}};
735+
}
736+
}
737+
727738
bool DummyArgument::IsOptional() const {
728739
return common::visit(
729740
common::visitors{
@@ -1132,6 +1143,30 @@ std::optional<Procedure> Procedure::Characterize(
11321143
return std::nullopt;
11331144
}
11341145

1146+
std::optional<Procedure> Procedure::FromActuals(const ProcedureDesignator &proc,
1147+
const ActualArguments &args, FoldingContext &context) {
1148+
auto callee{Characterize(proc, context)};
1149+
if (callee) {
1150+
if (callee->dummyArguments.empty() &&
1151+
callee->attrs.test(Procedure::Attr::ImplicitInterface)) {
1152+
int j{0};
1153+
for (const auto &arg : args) {
1154+
++j;
1155+
if (arg) {
1156+
if (auto dummy{DummyArgument::FromActual(
1157+
"x"s + std::to_string(j), *arg, context)}) {
1158+
callee->dummyArguments.emplace_back(std::move(*dummy));
1159+
continue;
1160+
}
1161+
}
1162+
callee.reset();
1163+
break;
1164+
}
1165+
}
1166+
}
1167+
return callee;
1168+
}
1169+
11351170
bool Procedure::CanBeCalledViaImplicitInterface() const {
11361171
// TODO: Pass back information on why we return false
11371172
if (attrs.test(Attr::Elemental) || attrs.test(Attr::BindC)) {

flang/lib/Semantics/expression.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,8 +2877,38 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
28772877
ActualArguments &arguments) {
28782878
bool treatExternalAsImplicit{IsExternalCalledImplicitly(callSite, proc)};
28792879
const Symbol *procSymbol{proc.GetSymbol()};
2880-
auto chars{characteristics::Procedure::Characterize(
2881-
proc, context_.foldingContext())};
2880+
std::optional<characteristics::Procedure> chars;
2881+
if (procSymbol && procSymbol->has<semantics::ProcEntityDetails>() &&
2882+
procSymbol->owner().IsGlobal()) {
2883+
// Unknown global external, implicit interface; assume
2884+
// characteristics from the actual arguments, and check
2885+
// for consistency with other references.
2886+
chars = characteristics::Procedure::FromActuals(
2887+
proc, arguments, context_.foldingContext());
2888+
if (chars && procSymbol) {
2889+
// Ensure calls over implicit interfaces are consistent
2890+
auto name{procSymbol->name()};
2891+
if (auto iter{implicitInterfaces_.find(name)};
2892+
iter != implicitInterfaces_.end()) {
2893+
std::string whyNot;
2894+
if (!chars->IsCompatibleWith(iter->second.second, &whyNot)) {
2895+
if (auto *msg{Say(callSite,
2896+
"Reference to the procedure '%s' has an implicit interface that is distinct from another reference: %s"_warn_en_US,
2897+
name, whyNot)}) {
2898+
msg->Attach(
2899+
iter->second.first, "previous reference to '%s'"_en_US, name);
2900+
}
2901+
}
2902+
} else {
2903+
implicitInterfaces_.insert(
2904+
std::make_pair(name, std::make_pair(callSite, *chars)));
2905+
}
2906+
}
2907+
}
2908+
if (!chars) {
2909+
chars = characteristics::Procedure::Characterize(
2910+
proc, context_.foldingContext());
2911+
}
28822912
bool ok{true};
28832913
if (chars) {
28842914
if (treatExternalAsImplicit && !chars->CanBeCalledViaImplicitInterface()) {

flang/test/Semantics/bad-forward-type.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55

66
!ERROR: The derived type 'undef' was forward-referenced but not defined
77
type(undef) function f1()
8-
call sub(f1)
8+
call sub1(f1)
99
end function
1010

1111
!ERROR: The derived type 'undef' was forward-referenced but not defined
1212
type(undef) function f2() result(r)
13-
call sub(r)
13+
call sub2(r)
1414
end function
1515

1616
!ERROR: The derived type 'undefpdt' was forward-referenced but not defined
1717
type(undefpdt(1)) function f3()
18-
call sub(f3)
18+
call sub3(f3)
1919
end function
2020

2121
!ERROR: The derived type 'undefpdt' was forward-referenced but not defined
2222
type(undefpdt(1)) function f4() result(r)
23-
call sub(f4)
23+
call sub4(f4)
2424
end function
2525

2626
!ERROR: 'bad' is not the name of a parameter for derived type 'pdt'

flang/test/Semantics/call35.f90

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
2+
subroutine s1
3+
call ext(1, 2)
4+
end
5+
6+
subroutine s2
7+
!WARNING: Reference to the procedure 'ext' has an implicit interface that is distinct from another reference: distinct numbers of dummy arguments
8+
call ext(1.)
9+
end
10+
11+
subroutine s3
12+
interface
13+
!WARNING: The global subprogram 'ext' is not compatible with its local procedure declaration (incompatible procedure attributes: ImplicitInterface)
14+
subroutine ext(n)
15+
integer n
16+
end
17+
end interface
18+
call ext(3)
19+
!ERROR: Actual argument type 'REAL(4)' is not compatible with dummy argument type 'INTEGER(4)'
20+
call ext(4.)
21+
end

flang/test/Semantics/reshape.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ program reshaper
4747
!ERROR: Size of 'shape=' argument must not be greater than 15
4848
CALL ext_sub(RESHAPE([(n, n=1,20)], &
4949
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]))
50+
!WARNING: Reference to the procedure 'ext_sub' has an implicit interface that is distinct from another reference: incompatible dummy argument #1: incompatible dummy data object shapes
5051
!ERROR: 'shape=' argument must not have a negative extent
5152
CALL ext_sub(RESHAPE([(n, n=1,20)], [1, -5, 3]))
5253
!ERROR: 'order=' argument has unacceptable rank 2

0 commit comments

Comments
 (0)