Skip to content

Commit d52a6e7

Browse files
committed
[flang] Process subprogram BIND(C,NAME=...) locally
The scalar-default-character-expression that defines the interoperable name of a function or subroutine (or interface) must have its names resolved within the context of the subprogram, despite its appearance on a function-stmt or a subroutine-stmt. Failure to do so can lead to bogus errors or to incorrect results. The solution is to defer name resolution for function-stmt suffixes (but not entry-stmt suffixes) and for subroutine-stmt language binding specifications to EndSubprogram(). (Their resolution only need to be deferred to the end of the specification part, but it's cleanest to deal with it in EndSubprogram().) Differential Revision: https://reviews.llvm.org/D126153
1 parent 2f93bbb commit d52a6e7

File tree

2 files changed

+100
-26
lines changed

2 files changed

+100
-26
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,6 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
809809
public:
810810
bool HandleStmtFunction(const parser::StmtFunctionStmt &);
811811
bool Pre(const parser::SubroutineStmt &);
812-
void Post(const parser::SubroutineStmt &);
813812
bool Pre(const parser::FunctionStmt &);
814813
void Post(const parser::FunctionStmt &);
815814
bool Pre(const parser::EntryStmt &);
@@ -827,7 +826,8 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
827826
const ProgramTree::EntryStmtList * = nullptr);
828827
bool BeginMpSubprogram(const parser::Name &);
829828
void PushBlockDataScope(const parser::Name &);
830-
void EndSubprogram();
829+
void EndSubprogram(
830+
const std::optional<parser::LanguageBindingSpec> * = nullptr);
831831

832832
protected:
833833
// Set when we see a stmt function that is really an array element assignment
@@ -3208,7 +3208,9 @@ bool SubprogramVisitor::Pre(const parser::Suffix &suffix) {
32083208
}
32093209
}
32103210
}
3211-
return true;
3211+
// LanguageBindingSpec deferred to Post(EntryStmt) or, for FunctionStmt,
3212+
// all the way to EndSubprogram().
3213+
return false;
32123214
}
32133215

32143216
bool SubprogramVisitor::Pre(const parser::PrefixSpec &x) {
@@ -3234,30 +3236,27 @@ bool SubprogramVisitor::Pre(const parser::InterfaceBody::Subroutine &x) {
32343236
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t)};
32353237
return BeginSubprogram(name, Symbol::Flag::Subroutine);
32363238
}
3237-
void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &) {
3238-
EndSubprogram();
3239+
void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &x) {
3240+
EndSubprogram(&std::get<std::optional<parser::LanguageBindingSpec>>(
3241+
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t));
32393242
}
32403243
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Function &x) {
32413244
const auto &name{std::get<parser::Name>(
32423245
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t)};
32433246
return BeginSubprogram(name, Symbol::Flag::Function);
32443247
}
3245-
void SubprogramVisitor::Post(const parser::InterfaceBody::Function &) {
3246-
EndSubprogram();
3247-
}
3248-
3249-
bool SubprogramVisitor::Pre(const parser::SubroutineStmt &) {
3250-
return BeginAttrs();
3251-
}
3252-
bool SubprogramVisitor::Pre(const parser::FunctionStmt &) {
3253-
FuncResultStack::FuncInfo &info{DEREF(funcResultStack().Top())};
3254-
CHECK(!info.inFunctionStmt);
3255-
info.inFunctionStmt = true;
3256-
return BeginAttrs();
3248+
void SubprogramVisitor::Post(const parser::InterfaceBody::Function &x) {
3249+
const auto &maybeSuffix{std::get<std::optional<parser::Suffix>>(
3250+
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t)};
3251+
EndSubprogram(maybeSuffix ? &maybeSuffix->binding : nullptr);
32573252
}
3258-
bool SubprogramVisitor::Pre(const parser::EntryStmt &) { return BeginAttrs(); }
32593253

3260-
void SubprogramVisitor::Post(const parser::SubroutineStmt &stmt) {
3254+
bool SubprogramVisitor::Pre(const parser::SubroutineStmt &stmt) {
3255+
BeginAttrs();
3256+
Walk(std::get<std::list<parser::PrefixSpec>>(stmt.t));
3257+
Walk(std::get<parser::Name>(stmt.t));
3258+
Walk(std::get<std::list<parser::DummyArg>>(stmt.t));
3259+
// Don't traverse the LanguageBindingSpec now; it's deferred to EndSubprogram.
32613260
const auto &name{std::get<parser::Name>(stmt.t)};
32623261
auto &details{PostSubprogramStmt(name)};
32633262
for (const auto &dummyArg : std::get<std::list<parser::DummyArg>>(stmt.t)) {
@@ -3268,7 +3267,15 @@ void SubprogramVisitor::Post(const parser::SubroutineStmt &stmt) {
32683267
details.add_alternateReturn();
32693268
}
32703269
}
3270+
return false;
32713271
}
3272+
bool SubprogramVisitor::Pre(const parser::FunctionStmt &) {
3273+
FuncResultStack::FuncInfo &info{DEREF(funcResultStack().Top())};
3274+
CHECK(!info.inFunctionStmt);
3275+
info.inFunctionStmt = true;
3276+
return BeginAttrs();
3277+
}
3278+
bool SubprogramVisitor::Pre(const parser::EntryStmt &) { return BeginAttrs(); }
32723279

32733280
void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
32743281
const auto &name{std::get<parser::Name>(stmt.t)};
@@ -3340,11 +3347,6 @@ void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
33403347
SubprogramDetails &SubprogramVisitor::PostSubprogramStmt(
33413348
const parser::Name &name) {
33423349
Symbol &symbol{*currScope().symbol()};
3343-
auto &subp{symbol.get<SubprogramDetails>()};
3344-
SetBindNameOn(symbol);
3345-
CHECK(name.source == symbol.name() ||
3346-
(subp.bindName() && symbol.owner().IsGlobal() &&
3347-
context().IsTempName(symbol.name().ToString())));
33483350
symbol.attrs() |= EndAttrs();
33493351
if (symbol.attrs().test(Attr::MODULE)) {
33503352
symbol.attrs().set(Attr::EXTERNAL, false);
@@ -3353,6 +3355,9 @@ SubprogramDetails &SubprogramVisitor::PostSubprogramStmt(
33533355
}
33543356

33553357
void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
3358+
if (const auto &suffix{std::get<std::optional<parser::Suffix>>(stmt.t)}) {
3359+
Walk(suffix->binding);
3360+
}
33563361
PostEntryStmt(stmt);
33573362
EndAttrs();
33583363
}
@@ -3592,7 +3597,19 @@ bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
35923597
return true;
35933598
}
35943599

3595-
void SubprogramVisitor::EndSubprogram() { PopScope(); }
3600+
void SubprogramVisitor::EndSubprogram(
3601+
const std::optional<parser::LanguageBindingSpec> *binding) {
3602+
if (binding && *binding && currScope().symbol()) {
3603+
// Finally process the BIND(C,NAME=name) now that symbols in the name
3604+
// expression will resolve local names.
3605+
auto flagRestorer{common::ScopedSet(inSpecificationPart_, false)};
3606+
BeginAttrs();
3607+
Walk(**binding);
3608+
SetBindNameOn(*currScope().symbol());
3609+
currScope().symbol()->attrs() |= EndAttrs();
3610+
}
3611+
PopScope();
3612+
}
35963613

35973614
bool SubprogramVisitor::HandlePreviousCalls(
35983615
const parser::Name &name, Symbol &symbol, Symbol::Flag subpFlag) {
@@ -7421,7 +7438,27 @@ bool ResolveNamesVisitor::BeginScopeForNode(const ProgramTree &node) {
74217438
}
74227439

74237440
void ResolveNamesVisitor::EndScopeForNode(const ProgramTree &node) {
7424-
EndSubprogram();
7441+
using BindingPtr = const std::optional<parser::LanguageBindingSpec> *;
7442+
EndSubprogram(common::visit(
7443+
common::visitors{
7444+
[](const parser::Statement<parser::FunctionStmt> *stmt) {
7445+
if (stmt) {
7446+
if (const auto &maybeSuffix{
7447+
std::get<std::optional<parser::Suffix>>(
7448+
stmt->statement.t)}) {
7449+
return &maybeSuffix->binding;
7450+
}
7451+
}
7452+
return BindingPtr{};
7453+
},
7454+
[](const parser::Statement<parser::SubroutineStmt> *stmt) {
7455+
return stmt ? &std::get<std::optional<parser::LanguageBindingSpec>>(
7456+
stmt->statement.t)
7457+
: BindingPtr{};
7458+
},
7459+
[](const auto *) { return BindingPtr{}; },
7460+
},
7461+
node.stmt()));
74257462
}
74267463

74277464
// Some analyses and checks, such as the processing of initializers of

flang/test/Lower/program-units-fir-mangling.f90

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,41 @@ subroutine sub_with_entries
185185
entry some_other_entry() bind(c)
186186
end subroutine
187187

188+
! Test that semantics constructs binding labels with local name resolution
189+
module testMod3
190+
character*(*), parameter :: foo = "bad!!"
191+
character*(*), parameter :: ok = "ok"
192+
interface
193+
real function f1() bind(c,name=ok//'1')
194+
import ok
195+
end function
196+
subroutine s1() bind(c,name=ok//'2')
197+
import ok
198+
end subroutine
199+
end interface
200+
contains
201+
! CHECK-LABEL: func @ok3() -> f32 attributes {fir.sym_name = "_QMtestmod3Pf2"} {
202+
real function f2() bind(c,name=foo//'3')
203+
character*(*), parameter :: foo = ok
204+
! CHECK: fir.call @ok1() : () -> f32
205+
! CHECK-LABEL: func @ok4() -> f32 attributes {fir.sym_name = "_QMtestmod3Pf3"} {
206+
entry f3() bind(c,name=foo//'4')
207+
! CHECK: fir.call @ok1() : () -> f32
208+
f2 = f1()
209+
end function
210+
! CHECK-LABEL: func @ok5() attributes {fir.sym_name = "_QMtestmod3Ps2"} {
211+
subroutine s2() bind(c,name=foo//'5')
212+
character*(*), parameter :: foo = ok
213+
! CHECK: fir.call @ok2() : () -> ()
214+
! CHECK-LABEL: func @ok6() attributes {fir.sym_name = "_QMtestmod3Ps3"} {
215+
entry s3() bind(c,name=foo//'6')
216+
! CHECK: fir.call @ok2() : () -> ()
217+
continue ! force end of specification part
218+
! CHECK-LABEL: func @ok7() attributes {fir.sym_name = "_QMtestmod3Ps4"} {
219+
entry s4() bind(c,name=foo//'7')
220+
! CHECK: fir.call @ok2() : () -> ()
221+
call s1
222+
end subroutine
223+
end module
224+
188225
! CHECK-LABEL: fir.global internal @_QFfooEpi : f32 {

0 commit comments

Comments
 (0)