Skip to content

Commit f19b807

Browse files
authored
[flang] Extend error checking for implicit interfaces (#155473)
When an external procedure is called by means of an implicit interface that turns out to be different in a significant way from the actual interface in its definition elsewhere in the source file, we emit an error message. This works for differences in actual vs dummy arguments, and for the result types of previously declared functions. This patch adds checking for differences between implicitly typed external function references and their actual declared types when the function's definition appears later.
1 parent 85b8b69 commit f19b807

File tree

2 files changed

+81
-17
lines changed

2 files changed

+81
-17
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,10 @@ class FuncResultStack {
488488
// Result symbol
489489
Symbol *resultSymbol{nullptr};
490490
bool inFunctionStmt{false}; // true between Pre/Post of FunctionStmt
491+
// Functions with previous implicitly-typed references get those types
492+
// checked against their later definitions.
493+
const DeclTypeSpec *previousImplicitType{nullptr};
494+
SourceName previousName;
491495
};
492496

493497
// Completes the definition of the top function's result.
@@ -943,7 +947,7 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
943947
// Edits an existing symbol created for earlier calls to a subprogram or ENTRY
944948
// so that it can be replaced by a later definition.
945949
bool HandlePreviousCalls(const parser::Name &, Symbol &, Symbol::Flag);
946-
void CheckExtantProc(const parser::Name &, Symbol::Flag);
950+
const Symbol *CheckExtantProc(const parser::Name &, Symbol::Flag);
947951
// Create a subprogram symbol in the current scope and push a new scope.
948952
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag,
949953
const parser::LanguageBindingSpec * = nullptr,
@@ -2691,11 +2695,17 @@ void ArraySpecVisitor::PostAttrSpec() {
26912695

26922696
FuncResultStack::~FuncResultStack() { CHECK(stack_.empty()); }
26932697

2698+
static bool TypesMismatchIfNonNull(
2699+
const DeclTypeSpec *type1, const DeclTypeSpec *type2) {
2700+
return type1 && type2 && *type1 != *type2;
2701+
}
2702+
26942703
void FuncResultStack::CompleteFunctionResultType() {
26952704
// If the function has a type in the prefix, process it now.
26962705
FuncInfo *info{Top()};
2697-
if (info && &info->scope == &scopeHandler_.currScope()) {
2698-
if (info->parsedType && info->resultSymbol) {
2706+
if (info && &info->scope == &scopeHandler_.currScope() &&
2707+
info->resultSymbol) {
2708+
if (info->parsedType) {
26992709
scopeHandler_.messageHandler().set_currStmtSource(info->source);
27002710
if (const auto *type{
27012711
scopeHandler_.ProcessTypeSpec(*info->parsedType, true)}) {
@@ -2712,6 +2722,16 @@ void FuncResultStack::CompleteFunctionResultType() {
27122722
}
27132723
info->parsedType = nullptr;
27142724
}
2725+
if (TypesMismatchIfNonNull(
2726+
info->resultSymbol->GetType(), info->previousImplicitType)) {
2727+
scopeHandler_
2728+
.Say(info->resultSymbol->name(),
2729+
"Function '%s' has a result type that differs from the implicit type it obtained in a previous reference"_err_en_US,
2730+
info->previousName)
2731+
.Attach(info->previousName,
2732+
"Previous reference implicitly typed as %s\n"_en_US,
2733+
info->previousImplicitType->AsFortran());
2734+
}
27152735
}
27162736
}
27172737

@@ -4761,9 +4781,7 @@ void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
47614781
if (info.resultName && !distinctResultName) {
47624782
context().Warn(common::UsageWarning::HomonymousResult,
47634783
info.resultName->source,
4764-
"The function name should not appear in RESULT; references to '%s' "
4765-
"inside the function will be considered as references to the "
4766-
"result only"_warn_en_US,
4784+
"The function name should not appear in RESULT; references to '%s' inside the function will be considered as references to the result only"_warn_en_US,
47674785
name.source);
47684786
// RESULT name was ignored above, the only side effect from doing so will be
47694787
// the inability to make recursive calls. The related parser::Name is still
@@ -5074,8 +5092,7 @@ bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
50745092
if (hasModulePrefix && !currScope().IsModule() &&
50755093
!currScope().IsSubmodule()) { // C1547
50765094
Say(name,
5077-
"'%s' is a MODULE procedure which must be declared within a "
5078-
"MODULE or SUBMODULE"_err_en_US);
5095+
"'%s' is a MODULE procedure which must be declared within a MODULE or SUBMODULE"_err_en_US);
50795096
// Don't return here because it can be useful to have the scope set for
50805097
// other semantic checks run before we print the errors
50815098
isValid = false;
@@ -5196,9 +5213,10 @@ bool SubprogramVisitor::HandlePreviousCalls(
51965213
}
51975214
}
51985215

5199-
void SubprogramVisitor::CheckExtantProc(
5216+
const Symbol *SubprogramVisitor::CheckExtantProc(
52005217
const parser::Name &name, Symbol::Flag subpFlag) {
5201-
if (auto *prev{FindSymbol(name)}) {
5218+
Symbol *prev{FindSymbol(name)};
5219+
if (prev) {
52025220
if (IsDummy(*prev)) {
52035221
} else if (auto *entity{prev->detailsIf<EntityDetails>()};
52045222
IsPointer(*prev) && entity && !entity->type()) {
@@ -5210,12 +5228,15 @@ void SubprogramVisitor::CheckExtantProc(
52105228
SayAlreadyDeclared(name, *prev);
52115229
}
52125230
}
5231+
return prev;
52135232
}
52145233

52155234
Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
52165235
Symbol::Flag subpFlag, const parser::LanguageBindingSpec *bindingSpec,
52175236
bool hasModulePrefix) {
52185237
Symbol *symbol{GetSpecificFromGeneric(name)};
5238+
const DeclTypeSpec *previousImplicitType{nullptr};
5239+
SourceName previousName;
52195240
if (!symbol) {
52205241
if (bindingSpec && currScope().IsGlobal() &&
52215242
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
@@ -5228,14 +5249,25 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
52285249
&MakeSymbol(context().GetTempName(currScope()), Attrs{},
52295250
MiscDetails{MiscDetails::Kind::ScopeName}));
52305251
}
5231-
CheckExtantProc(name, subpFlag);
5252+
if (const Symbol *previous{CheckExtantProc(name, subpFlag)}) {
5253+
if (previous->test(Symbol::Flag::Function) &&
5254+
previous->test(Symbol::Flag::Implicit)) {
5255+
// Function was implicitly typed in previous compilation unit.
5256+
previousImplicitType = previous->GetType();
5257+
previousName = previous->name();
5258+
}
5259+
}
52325260
symbol = &MakeSymbol(name, SubprogramDetails{});
52335261
}
52345262
symbol->ReplaceName(name.source);
52355263
symbol->set(subpFlag);
52365264
PushScope(Scope::Kind::Subprogram, symbol);
52375265
if (subpFlag == Symbol::Flag::Function) {
5238-
funcResultStack().Push(currScope(), name.source);
5266+
auto &funcResultTop{funcResultStack().Push(currScope(), name.source)};
5267+
funcResultTop.previousImplicitType = previousImplicitType;
5268+
;
5269+
funcResultTop.previousName = previousName;
5270+
;
52395271
}
52405272
if (inInterfaceBlock()) {
52415273
auto &details{symbol->get<SubprogramDetails>()};
@@ -8669,11 +8701,6 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
86698701
x.u);
86708702
}
86718703

8672-
static bool TypesMismatchIfNonNull(
8673-
const DeclTypeSpec *type1, const DeclTypeSpec *type2) {
8674-
return type1 && type2 && *type1 != *type2;
8675-
}
8676-
86778704
// If implicit types are allowed, ensure name is in the symbol table.
86788705
// Otherwise, report an error if it hasn't been declared.
86798706
const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {

flang/test/Semantics/global02.f90

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
2+
! Catch discrepancies between implicit result types and a global definition
3+
4+
complex function zbefore()
5+
zbefore = (0.,0.)
6+
end
7+
8+
program main
9+
!ERROR: Implicit declaration of function 'zbefore' has a different result type than in previous declaration
10+
print *, zbefore()
11+
print *, zafter()
12+
print *, zafter2()
13+
print *, zafter3()
14+
end
15+
16+
subroutine another
17+
implicit integer(z)
18+
!ERROR: Implicit declaration of function 'zafter' has a different result type than in previous declaration
19+
print *, zafter()
20+
end
21+
22+
!ERROR: Function 'zafter' has a result type that differs from the implicit type it obtained in a previous reference
23+
complex function zafter()
24+
zafter = (0.,0.)
25+
end
26+
27+
function zafter2()
28+
!ERROR: Function 'zafter2' has a result type that differs from the implicit type it obtained in a previous reference
29+
complex zafter2
30+
zafter2 = (0.,0.)
31+
end
32+
33+
function zafter3() result(res)
34+
!ERROR: Function 'zafter3' has a result type that differs from the implicit type it obtained in a previous reference
35+
complex res
36+
res = (0.,0.)
37+
end

0 commit comments

Comments
 (0)