[flang-commits] [flang] 7c71ce9 - [flang] Defer NAMELIST group item name resolution
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Thu Apr 14 17:50:11 PDT 2022
Author: Peter Klausler
Date: 2022-04-14T17:50:03-07:00
New Revision: 7c71ce97e7be0a00322459527564ad1194e1e4b5
URL: https://github.com/llvm/llvm-project/commit/7c71ce97e7be0a00322459527564ad1194e1e4b5
DIFF: https://github.com/llvm/llvm-project/commit/7c71ce97e7be0a00322459527564ad1194e1e4b5.diff
LOG: [flang] Defer NAMELIST group item name resolution
Items in NAMELIST groups might be host-associated implicitly-typed
variables, but name resolution can't know that when the NAMELIST
appears in a specification part and the host's execution part has
not yet been analyzed. So defer NAMELIST group item name resolution
to the end of the execution part. This is safe because nothing
else in name resolution depends on whether a variable is in a
NAMELIST group or not.
Differential Revision: https://reviews.llvm.org/D123723
Added:
Modified:
flang/lib/Semantics/resolve-names.cpp
flang/test/Semantics/call19.f90
flang/test/Semantics/resolve40.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 15cc77328b34e..2e693f82220a9 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -667,9 +667,26 @@ class ScopeHandler : public ImplicitRulesVisitor {
} saveInfo;
} specPartState_;
+ // Some declaration processing can and should be deferred to
+ // ResolveExecutionParts() to avoid prematurely creating implicitly-typed
+ // local symbols that should be host associations.
+ struct DeferredDeclarationState {
+ // The content of each namelist group
+ std::list<const parser::NamelistStmt::Group *> namelistGroups;
+ };
+ DeferredDeclarationState *GetDeferredDeclarationState(bool add = false) {
+ if (!add && deferred_.find(&currScope()) == deferred_.end()) {
+ return nullptr;
+ } else {
+ return &deferred_.emplace(&currScope(), DeferredDeclarationState{})
+ .first->second;
+ }
+ }
+
private:
Scope *currScope_{nullptr};
FuncResultStack funcResultStack_{*this};
+ std::map<Scope *, DeferredDeclarationState> deferred_;
};
class ModuleVisitor : public virtual ScopeHandler {
@@ -960,6 +977,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
void CheckEquivalenceSets();
bool CheckNotInBlock(const char *);
bool NameIsKnownOrIntrinsic(const parser::Name &);
+ void FinishNamelists();
// Each of these returns a pointer to a resolved Name (i.e. with symbol)
// or nullptr in case of error.
@@ -4986,30 +5004,41 @@ bool DeclarationVisitor::Pre(const parser::NamelistStmt::Group &x) {
if (!CheckNotInBlock("NAMELIST")) { // C1107
return false;
}
-
- NamelistDetails details;
- for (const auto &name : std::get<std::list<parser::Name>>(x.t)) {
- auto *symbol{FindSymbol(name)};
- if (!symbol) {
- symbol = &MakeSymbol(name, ObjectEntityDetails{});
- ApplyImplicitRules(*symbol);
- } else if (!ConvertToObjectEntity(*symbol)) {
- SayWithDecl(name, *symbol, "'%s' is not a variable"_err_en_US);
- }
- symbol->GetUltimate().set(Symbol::Flag::InNamelist);
- details.add_object(*symbol);
- }
-
const auto &groupName{std::get<parser::Name>(x.t)};
auto *groupSymbol{FindInScope(groupName)};
if (!groupSymbol || !groupSymbol->has<NamelistDetails>()) {
- groupSymbol = &MakeSymbol(groupName, std::move(details));
+ groupSymbol = &MakeSymbol(groupName, NamelistDetails{});
groupSymbol->ReplaceName(groupName.source);
}
- groupSymbol->get<NamelistDetails>().add_objects(details.objects());
+ // Name resolution of group items is deferred to FinishNamelists()
+ // so that host association is handled correctly.
+ GetDeferredDeclarationState(true)->namelistGroups.emplace_back(&x);
return false;
}
+void DeclarationVisitor::FinishNamelists() {
+ if (auto *deferred{GetDeferredDeclarationState()}) {
+ for (const parser::NamelistStmt::Group *group : deferred->namelistGroups) {
+ if (auto *groupSymbol{FindInScope(std::get<parser::Name>(group->t))}) {
+ if (auto *details{groupSymbol->detailsIf<NamelistDetails>()}) {
+ for (const auto &name : std::get<std::list<parser::Name>>(group->t)) {
+ auto *symbol{FindSymbol(name)};
+ if (!symbol) {
+ symbol = &MakeSymbol(name, ObjectEntityDetails{});
+ ApplyImplicitRules(*symbol);
+ } else if (!ConvertToObjectEntity(*symbol)) {
+ SayWithDecl(name, *symbol, "'%s' is not a variable"_err_en_US);
+ }
+ symbol->GetUltimate().set(Symbol::Flag::InNamelist);
+ details->add_object(*symbol);
+ }
+ }
+ }
+ }
+ deferred->namelistGroups.clear();
+ }
+}
+
bool DeclarationVisitor::Pre(const parser::IoControlSpec &x) {
if (const auto *name{std::get_if<parser::Name>(&x.u)}) {
auto *symbol{FindSymbol(*name)};
@@ -7447,6 +7476,7 @@ void ResolveNamesVisitor::ResolveExecutionParts(const ProgramTree &node) {
if (const auto *exec{node.exec()}) {
Walk(*exec);
}
+ FinishNamelists();
PopScope(); // converts unclassified entities into objects
for (const auto &child : node.children()) {
ResolveExecutionParts(child);
diff --git a/flang/test/Semantics/call19.f90 b/flang/test/Semantics/call19.f90
index 753ff95d280df..3cca46c93ce0b 100644
--- a/flang/test/Semantics/call19.f90
+++ b/flang/test/Semantics/call19.f90
@@ -10,6 +10,7 @@ module m
integer, len :: len
end type
type(pdt(1,2)) :: x
+ !ERROR: 'i' is not a variable
namelist /nml/i
contains
subroutine s(d)
diff --git a/flang/test/Semantics/resolve40.f90 b/flang/test/Semantics/resolve40.f90
index 331c5ebd02c0e..310b3c3872a0f 100644
--- a/flang/test/Semantics/resolve40.f90
+++ b/flang/test/Semantics/resolve40.f90
@@ -40,7 +40,6 @@ subroutine s4b
subroutine s5
namelist /nl/x
- !ERROR: The type of 'x' has already been implicitly declared
integer x
end
@@ -57,8 +56,8 @@ integer function f()
subroutine s7
real x
+ !ERROR: 'x' is not a variable
namelist /nl/ x
- !ERROR: EXTERNAL attribute not allowed on 'x'
external x
end
More information about the flang-commits
mailing list