Skip to content

Commit fbbd8b0

Browse files
authored
[flang] Fix rewriting of misparsed statement functions (#112934)
Fortran's syntax is ambiguous for some assignment statements (to array elements or to the targets of pointers returned by functions) that appear as the first executable statements in a subprogram or BLOCK construct. Is A(I)=X a statement function definition at the end of the specification part, or ar array element assignment statement, or an assignment to a pointer returned by a function named A? Since f18 builds a parse tree for the entire source file before beginning any semantic analysis, we can't tell which is which until after name resolution, at which point the symbol table has been built. So we have to walk the parse tree and rewrite some misparsed statement function definitions that really were assignment statements. There's a bug in that code, though, due to the fact that the implementation used state in the parse tree walker to hold a list of misparsed statement function definitions extracted from one specification part to be reinserted at the beginning of the next execution part that is visited; it didn't work for misparsed cases BLOCK constructs. Their parse tree nodes encapsulate a parser::Block, not an instance of the wrapper class parser::ExecutionPart. So misparsed statement functions in BLOCK constructs were being rewritten into assignment statement that were inserted at the beginning of the executable part of the following subprogram, if and wherever one happened to occur. This led to crashes in lowering and much astonishment. A simple fix would have been to adjust the rewriting code to always insert the list at the next visited parser::Block, since parser::ExecutionPart is just a wrapper around Block anyway; but this patch goes further to do the "right thing", which is a restructuring of the rewrite that avoids the use of state and any assumptions about parse tree walking visitation order. Fixes #112549.
1 parent e8644e3 commit fbbd8b0

File tree

2 files changed

+103
-25
lines changed

2 files changed

+103
-25
lines changed

flang/lib/Semantics/rewrite-parse-tree.cpp

+53-25
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ class RewriteMutator {
4040
template <typename T> void Post(T &) {}
4141

4242
void Post(parser::Name &);
43-
void Post(parser::SpecificationPart &);
44-
bool Pre(parser::ExecutionPart &);
43+
bool Pre(parser::MainProgram &);
44+
bool Pre(parser::FunctionSubprogram &);
45+
bool Pre(parser::SubroutineSubprogram &);
46+
bool Pre(parser::SeparateModuleSubprogram &);
47+
bool Pre(parser::BlockConstruct &);
4548
bool Pre(parser::ActionStmt &);
4649
void Post(parser::ReadStmt &);
4750
void Post(parser::WriteStmt &);
@@ -65,12 +68,11 @@ class RewriteMutator {
6568
bool Pre(parser::EndTypeStmt &) { return false; }
6669

6770
private:
68-
using stmtFuncType =
69-
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
71+
void FixMisparsedStmtFuncs(parser::SpecificationPart &, parser::Block &);
72+
7073
SemanticsContext &context_;
7174
bool errorOnUnresolvedName_{true};
7275
parser::Messages &messages_;
73-
std::list<stmtFuncType> stmtFuncsToConvert_;
7476
};
7577

7678
// Check that name has been resolved to a symbol
@@ -94,41 +96,67 @@ static bool ReturnsDataPointer(const Symbol &symbol) {
9496
return false;
9597
}
9698

97-
// Find mis-parsed statement functions and move to stmtFuncsToConvert_ list.
98-
void RewriteMutator::Post(parser::SpecificationPart &x) {
99-
auto &list{std::get<std::list<parser::DeclarationConstruct>>(x.t)};
99+
// Finds misparsed statement functions in a specification part, rewrites
100+
// them into array element assignment statements, and moves them into the
101+
// beginning of the corresponding (execution part's) block.
102+
void RewriteMutator::FixMisparsedStmtFuncs(
103+
parser::SpecificationPart &specPart, parser::Block &block) {
104+
auto &list{std::get<std::list<parser::DeclarationConstruct>>(specPart.t)};
105+
auto origFirst{block.begin()}; // insert each elem before origFirst
100106
for (auto it{list.begin()}; it != list.end();) {
101-
bool isAssignment{false};
102-
if (auto *stmt{std::get_if<stmtFuncType>(&it->u)}) {
107+
bool convert{false};
108+
if (auto *stmt{std::get_if<
109+
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>(
110+
&it->u)}) {
103111
if (const Symbol *
104112
symbol{std::get<parser::Name>(stmt->statement.value().t).symbol}) {
105113
const Symbol &ultimate{symbol->GetUltimate()};
106-
isAssignment =
114+
convert =
107115
ultimate.has<ObjectEntityDetails>() || ReturnsDataPointer(ultimate);
108-
if (isAssignment) {
109-
stmtFuncsToConvert_.emplace_back(std::move(*stmt));
116+
if (convert) {
117+
auto newStmt{stmt->statement.value().ConvertToAssignment()};
118+
newStmt.source = stmt->source;
119+
block.insert(origFirst,
120+
parser::ExecutionPartConstruct{
121+
parser::ExecutableConstruct{std::move(newStmt)}});
110122
}
111123
}
112124
}
113-
if (isAssignment) {
125+
if (convert) {
114126
it = list.erase(it);
115127
} else {
116128
++it;
117129
}
118130
}
119131
}
120132

121-
// Insert converted assignments at start of ExecutionPart.
122-
bool RewriteMutator::Pre(parser::ExecutionPart &x) {
123-
auto origFirst{x.v.begin()}; // insert each elem before origFirst
124-
for (stmtFuncType &sf : stmtFuncsToConvert_) {
125-
auto stmt{sf.statement.value().ConvertToAssignment()};
126-
stmt.source = sf.source;
127-
x.v.insert(origFirst,
128-
parser::ExecutionPartConstruct{
129-
parser::ExecutableConstruct{std::move(stmt)}});
130-
}
131-
stmtFuncsToConvert_.clear();
133+
bool RewriteMutator::Pre(parser::MainProgram &program) {
134+
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(program.t),
135+
std::get<parser::ExecutionPart>(program.t).v);
136+
return true;
137+
}
138+
139+
bool RewriteMutator::Pre(parser::FunctionSubprogram &func) {
140+
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(func.t),
141+
std::get<parser::ExecutionPart>(func.t).v);
142+
return true;
143+
}
144+
145+
bool RewriteMutator::Pre(parser::SubroutineSubprogram &subr) {
146+
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subr.t),
147+
std::get<parser::ExecutionPart>(subr.t).v);
148+
return true;
149+
}
150+
151+
bool RewriteMutator::Pre(parser::SeparateModuleSubprogram &subp) {
152+
FixMisparsedStmtFuncs(std::get<parser::SpecificationPart>(subp.t),
153+
std::get<parser::ExecutionPart>(subp.t).v);
154+
return true;
155+
}
156+
157+
bool RewriteMutator::Pre(parser::BlockConstruct &block) {
158+
FixMisparsedStmtFuncs(std::get<parser::BlockSpecificationPart>(block.t).v,
159+
std::get<parser::Block>(block.t));
132160
return true;
133161
}
134162

flang/test/Semantics/rewrite03.f90

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
!RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
!Test rewriting of misparsed statement function definitions
3+
!into array element assignment statements.
4+
5+
program main
6+
real sf(1)
7+
integer :: j = 1
8+
!CHECK: sf(int(j,kind=8))=1._4
9+
sf(j) = 1.
10+
end
11+
12+
function func
13+
real sf(1)
14+
integer :: j = 1
15+
!CHECK: sf(int(j,kind=8))=2._4
16+
sf(j) = 2.
17+
func = 0.
18+
end
19+
20+
subroutine subr
21+
real sf(1)
22+
integer :: j = 1
23+
!CHECK: sf(int(j,kind=8))=3._4
24+
sf(j) = 3.
25+
end
26+
27+
module m
28+
interface
29+
module subroutine smp
30+
end
31+
end interface
32+
end
33+
submodule(m) sm
34+
contains
35+
module procedure smp
36+
real sf(1)
37+
integer :: j = 1
38+
!CHECK: sf(int(j,kind=8))=4._4
39+
sf(j) = 4.
40+
end
41+
end
42+
43+
subroutine block
44+
block
45+
real sf(1)
46+
integer :: j = 1
47+
!CHECK: sf(int(j,kind=8))=5._4
48+
sf(j) = 5.
49+
end block
50+
end

0 commit comments

Comments
 (0)