diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -831,7 +831,8 @@ bool BeginMpSubprogram(const parser::Name &); void PushBlockDataScope(const parser::Name &); void EndSubprogram(std::optional stmtSource = std::nullopt, - const std::optional * = nullptr); + const std::optional * = nullptr, + const ProgramTree::EntryStmtList * = nullptr); protected: // Set when we see a stmt function that is really an array element assignment @@ -849,6 +850,9 @@ SubprogramDetails &PostSubprogramStmt(const parser::Name &); void CreateEntry(const parser::EntryStmt &stmt, Symbol &subprogram); void PostEntryStmt(const parser::EntryStmt &stmt); + void HandleLanguageBinding(Symbol *, + std::optional stmtSource, + const std::optional *); }; class DeclarationVisitor : public ArraySpecVisitor, @@ -3457,20 +3461,24 @@ ? Symbol::Flag::Function : Symbol::Flag::Subroutine}; Attrs attrs; - if (Symbol * extant{FindSymbol(outer, entryName)}) { - if (!HandlePreviousCalls(entryName, *extant, subpFlag)) { - if (outer.IsTopLevel()) { - Say2(entryName, - "'%s' is already defined as a global identifier"_err_en_US, *extant, - "Previous definition of '%s'"_en_US); - } else { - SayAlreadyDeclared(entryName, *extant); + const auto &suffix{std::get>(stmt.t)}; + bool hasGlobalBindingName{outer.IsGlobal() && suffix && suffix->binding && + suffix->binding->v.has_value()}; + if (!hasGlobalBindingName) { + if (Symbol * extant{FindSymbol(outer, entryName)}) { + if (!HandlePreviousCalls(entryName, *extant, subpFlag)) { + if (outer.IsTopLevel()) { + Say2(entryName, + "'%s' is already defined as a global identifier"_err_en_US, + *extant, "Previous definition of '%s'"_en_US); + } else { + SayAlreadyDeclared(entryName, *extant); + } + return; } - return; + attrs = extant->attrs(); } - attrs = extant->attrs(); } - const auto &suffix{std::get>(stmt.t)}; bool badResultName{false}; std::optional distinctResultName; if (suffix && suffix->resultName && @@ -3496,17 +3504,27 @@ if (outer.IsModule() && !attrs.test(Attr::PRIVATE)) { attrs.set(Attr::PUBLIC); } - Symbol *entrySymbol{FindInScope(outer, entryName.source)}; - if (entrySymbol) { - if (auto *generic{entrySymbol->detailsIf()}) { - if (auto *specific{generic->specific()}) { - // Forward reference to ENTRY from a generic interface - entrySymbol = specific; - entrySymbol->attrs() |= attrs; + Symbol *entrySymbol{nullptr}; + if (hasGlobalBindingName) { + // Hide the entry's symbol in a new anonymous global scope so + // that its name doesn't clash with anything. + Symbol &symbol{MakeSymbol(outer, context().GetTempName(outer), Attrs{})}; + symbol.set_details(MiscDetails{MiscDetails::Kind::ScopeName}); + Scope &hidden{outer.MakeScope(Scope::Kind::Global, &symbol)}; + entrySymbol = &MakeSymbol(hidden, entryName.source, attrs); + } else { + entrySymbol = FindInScope(outer, entryName.source); + if (entrySymbol) { + if (auto *generic{entrySymbol->detailsIf()}) { + if (auto *specific{generic->specific()}) { + // Forward reference to ENTRY from a generic interface + entrySymbol = specific; + entrySymbol->attrs() |= attrs; + } } + } else { + entrySymbol = &MakeSymbol(outer, entryName.source, attrs); } - } else { - entrySymbol = &MakeSymbol(outer, entryName.source, attrs); } SubprogramDetails entryDetails; entryDetails.set_entryScope(currScope()); @@ -3696,21 +3714,38 @@ return true; } -void SubprogramVisitor::EndSubprogram( +void SubprogramVisitor::HandleLanguageBinding(Symbol *symbol, std::optional stmtSource, const std::optional *binding) { - if (binding && *binding && currScope().symbol()) { + if (binding && *binding && symbol) { // Finally process the BIND(C,NAME=name) now that symbols in the name - // expression will resolve local names. + // expression will resolve to local names if needed. auto flagRestorer{common::ScopedSet(inSpecificationPart_, false)}; auto originalStmtSource{messageHandler().currStmtSource()}; messageHandler().set_currStmtSource(stmtSource); BeginAttrs(); Walk(**binding); - SetBindNameOn(*currScope().symbol()); - currScope().symbol()->attrs() |= EndAttrs(); + SetBindNameOn(*symbol); + symbol->attrs() |= EndAttrs(); messageHandler().set_currStmtSource(originalStmtSource); } +} + +void SubprogramVisitor::EndSubprogram( + std::optional stmtSource, + const std::optional *binding, + const ProgramTree::EntryStmtList *entryStmts) { + HandleLanguageBinding(currScope().symbol(), stmtSource, binding); + if (entryStmts) { + for (const auto &ref : *entryStmts) { + const parser::EntryStmt &entryStmt{*ref}; + if (const auto &suffix{ + std::get>(entryStmt.t)}) { + const auto &name{std::get(entryStmt.t)}; + HandleLanguageBinding(name.symbol, name.source, &suffix->binding); + } + } + } PopScope(); } @@ -7607,7 +7642,7 @@ [](const auto *) {}, }, node.stmt()); - EndSubprogram(stmtSource, binding); + EndSubprogram(stmtSource, binding, &node.entryStmts()); } // Some analyses and checks, such as the processing of initializers of diff --git a/flang/test/Semantics/symbol24.f90 b/flang/test/Semantics/symbol24.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/symbol24.f90 @@ -0,0 +1,20 @@ +! RUN: %python %S/test_symbols.py %s %flang_fc1 +! Ensure that global ENTRY symbols with global bindings +! are hidden in distinct global scopes, and nothing +! clashes so long as binding names are distinct. + +!DEF: /s1 (Subroutine) Subprogram +subroutine s1 + !DEF: /foo (Subroutine) Subprogram + entry foo() +end subroutine +!DEF: /s2 (Subroutine) Subprogram +subroutine s2 + !DEF: /foo BIND(C) (Subroutine) Subprogram + entry foo() bind(c, name="foo1") +end subroutine +!DEF: /s3 (Subroutine) Subprogram +subroutine s3 + !DEF: /foo BIND(C) (Subroutine) Subprogram + entry foo() bind(c, name="foo2") +end subroutine