Skip to content

Commit 8b29048

Browse files
committed
[flang] Correct disambiguation of possible statement function definitions
The statement "A(J) = expr" could be an assignment to an element of an array A, an assignment to the target of a pointer-valued function A, or the definition of a new statement function in the local scope named A, depending on whether it appears in (what might still be) the specification part of a program or subprogram and what other declarations and definitions for A might exist in the local scope or have been imported into it. The standard requires that the name of a statement function appear in an earlier type declaration statement if it is also the name of an entity in the enclosing scope. Some other Fortran compilers mistakenly enforce that rule in the case of an assignment to the target of a pointer-valued function in the containing scope, after misinterpreting the assignment as a new local statement function definition. This patch cleans up the handling of the various possibilities and resolves what was a crash in the case of a statement function definition whose name was the same as that of a procedure in the outer scope whose result is *not* a pointer. Differential Revision: https://reviews.llvm.org/D155493
1 parent 22ed61e commit 8b29048

File tree

5 files changed

+75
-16
lines changed

5 files changed

+75
-16
lines changed

flang/include/flang/Semantics/tools.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,5 +662,7 @@ inline const parser::Name *getDesignatorNameIfDataRef(
662662
return dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr;
663663
}
664664

665+
bool CouldBeDataPointerValuedFunction(const Symbol *);
666+
665667
} // namespace Fortran::semantics
666668
#endif // FORTRAN_SEMANTICS_TOOLS_H_

flang/lib/Semantics/resolve-names.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
879879

880880
protected:
881881
// Set when we see a stmt function that is really an array element assignment
882-
bool badStmtFuncFound_{false};
882+
bool misparsedStmtFuncFound_{false};
883883

884884
private:
885885
// Edits an existing symbol created for earlier calls to a subprogram or ENTRY
@@ -2313,6 +2313,7 @@ void ScopeHandler::PushScope(Scope &scope) {
23132313
}
23142314
}
23152315
void ScopeHandler::PopScope() {
2316+
CHECK(currScope_ && !currScope_->IsGlobal());
23162317
// Entities that are not yet classified as objects or procedures are now
23172318
// assumed to be objects.
23182319
// TODO: Statement functions
@@ -3439,18 +3440,27 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
34393440
const DeclTypeSpec *resultType{nullptr};
34403441
// Look up name: provides return type or tells us if it's an array
34413442
if (auto *symbol{FindSymbol(name)}) {
3442-
auto *details{symbol->detailsIf<EntityDetails>()};
3443-
if (!details || symbol->has<ObjectEntityDetails>() ||
3444-
symbol->has<ProcEntityDetails>()) {
3445-
badStmtFuncFound_ = true;
3443+
Symbol &ultimate{symbol->GetUltimate()};
3444+
if (ultimate.has<ObjectEntityDetails>() ||
3445+
CouldBeDataPointerValuedFunction(&ultimate)) {
3446+
misparsedStmtFuncFound_ = true;
34463447
return false;
34473448
}
3448-
// TODO: check that attrs are compatible with stmt func
3449-
resultType = details->type();
3450-
symbol->details() = UnknownDetails{}; // will be replaced below
3449+
if (DoesScopeContain(&ultimate.owner(), currScope())) {
3450+
Say(name,
3451+
"Name '%s' from host scope should have a type declaration before its local statement function definition"_port_en_US);
3452+
MakeSymbol(name, Attrs{}, UnknownDetails{});
3453+
} else if (auto *entity{ultimate.detailsIf<EntityDetails>()};
3454+
entity && !ultimate.has<ProcEntityDetails>()) {
3455+
resultType = entity->type();
3456+
ultimate.details() = UnknownDetails{}; // will be replaced below
3457+
} else {
3458+
misparsedStmtFuncFound_ = true;
3459+
}
34513460
}
3452-
if (badStmtFuncFound_) {
3453-
Say(name, "'%s' has not been declared as an array"_err_en_US);
3461+
if (misparsedStmtFuncFound_) {
3462+
Say(name,
3463+
"'%s' has not been declared as an array or pointer-valued function"_err_en_US);
34543464
return false;
34553465
}
34563466
auto &symbol{PushSubprogramScope(name, Symbol::Flag::Function)};
@@ -7847,7 +7857,7 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
78477857

78487858
void ResolveNamesVisitor::FinishSpecificationPart(
78497859
const std::list<parser::DeclarationConstruct> &decls) {
7850-
badStmtFuncFound_ = false;
7860+
misparsedStmtFuncFound_ = false;
78517861
funcResultStack().CompleteFunctionResultType();
78527862
CheckImports();
78537863
bool inModule{currScope().kind() == Scope::Kind::Module};
@@ -7903,8 +7913,9 @@ void ResolveNamesVisitor::AnalyzeStmtFunctionStmt(
79037913
const auto &name{std::get<parser::Name>(stmtFunc.t)};
79047914
Symbol *symbol{name.symbol};
79057915
auto *details{symbol ? symbol->detailsIf<SubprogramDetails>() : nullptr};
7906-
if (!details || !symbol->scope()) {
7907-
return;
7916+
if (!details || !symbol->scope() ||
7917+
&symbol->scope()->parent() != &currScope()) {
7918+
return; // error recovery
79087919
}
79097920
// Resolve the symbols on the RHS of the statement function.
79107921
PushScope(*symbol->scope());
@@ -8031,7 +8042,8 @@ bool ResolveNamesVisitor::Pre(const parser::StmtFunctionStmt &x) {
80318042
if (HandleStmtFunction(x)) {
80328043
return false;
80338044
} else {
8034-
// This is an array element assignment: resolve names of indices
8045+
// This is an array element or pointer-valued function assignment:
8046+
// resolve the names of indices/arguments
80358047
const auto &names{std::get<std::list<parser::Name>>(x.t)};
80368048
for (auto &name : names) {
80378049
ResolveName(name);

flang/lib/Semantics/tools.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,4 +1629,21 @@ void WarnOnDeferredLengthCharacterScalar(SemanticsContext &context,
16291629
}
16301630
}
16311631

1632+
bool CouldBeDataPointerValuedFunction(const Symbol *original) {
1633+
if (original) {
1634+
const Symbol &ultimate{original->GetUltimate()};
1635+
if (const Symbol * result{FindFunctionResult(ultimate)}) {
1636+
return IsPointer(*result) && !IsProcedure(*result);
1637+
}
1638+
if (const auto *generic{ultimate.detailsIf<GenericDetails>()}) {
1639+
for (const SymbolRef &ref : generic->specificProcs()) {
1640+
if (CouldBeDataPointerValuedFunction(&*ref)) {
1641+
return true;
1642+
}
1643+
}
1644+
}
1645+
}
1646+
return false;
1647+
}
1648+
16321649
} // namespace Fortran::semantics

flang/test/Semantics/resolve08.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1
22
integer :: g(10)
33
f(i) = i + 1 ! statement function
4-
g(i) = i + 2 ! mis-parsed array assignment
5-
!ERROR: 'h' has not been declared as an array
4+
g(i) = i + 2 ! mis-parsed assignment
5+
!ERROR: 'h' has not been declared as an array or pointer-valued function
66
h(i) = i + 3
77
end

flang/test/Semantics/stmt-func02.f90

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
module m
3+
real, target :: x = 1.
4+
contains
5+
function rpf(x)
6+
real, intent(in out), target :: x
7+
real, pointer :: rpf
8+
rpf => x
9+
end
10+
real function rf(x)
11+
rf = x
12+
end
13+
subroutine test1
14+
! This is a valid assignment, not a statement function.
15+
! Every other Fortran compiler misinterprets it!
16+
rpf(x) = 2. ! statement function or indirect assignment?
17+
print *, x
18+
end
19+
subroutine test2
20+
!PORTABILITY: Name 'rf' from host scope should have a type declaration before its local statement function definition
21+
rf(x) = 3.
22+
end
23+
subroutine test3
24+
external sf
25+
!ERROR: 'sf' has not been declared as an array or pointer-valued function
26+
sf(x) = 4.
27+
end
28+
end

0 commit comments

Comments
 (0)