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 @@ -1010,9 +1010,9 @@ bool Pre(const parser::BlockStmt &); bool Pre(const parser::EndBlockStmt &); void Post(const parser::Selector &); - bool Pre(const parser::AssociateStmt &); + void Post(const parser::AssociateStmt &); void Post(const parser::EndAssociateStmt &); - void Post(const parser::Association &); + bool Pre(const parser::Association &); void Post(const parser::SelectTypeStmt &); void Post(const parser::SelectRankStmt &); bool Pre(const parser::SelectTypeConstruct &); @@ -1081,6 +1081,7 @@ Selector selector; }; std::vector associationStack_; + Association *currentAssociation_{nullptr}; template bool CheckDef(const T &t) { return CheckDef(std::get>(t)); @@ -1098,9 +1099,10 @@ void SetAttrsFromAssociation(Symbol &); Selector ResolveSelector(const parser::Selector &); void ResolveIndexName(const parser::ConcurrentControl &control); + void SetCurrentAssociation(std::size_t n); Association &GetCurrentAssociation(); void PushAssociation(); - void PopAssociation(); + void PopAssociation(std::size_t count = 1); }; // Create scopes for OpenACC constructs @@ -5153,29 +5155,33 @@ GetCurrentAssociation().selector = ResolveSelector(x); } -bool ConstructVisitor::Pre(const parser::AssociateStmt &x) { +void ConstructVisitor::Post(const parser::AssociateStmt &x) { CheckDef(x.t); PushScope(Scope::Kind::Block, nullptr); - PushAssociation(); - return true; + const auto assocCount{std::get>(x.t).size()}; + for (auto nthLastAssoc{assocCount}; nthLastAssoc > 0; --nthLastAssoc) { + SetCurrentAssociation(nthLastAssoc); + if (auto *symbol{MakeAssocEntity()}) { + if (ExtractCoarrayRef(GetCurrentAssociation().selector.expr)) { // C1103 + Say("Selector must not be a coindexed object"_err_en_US); + } + SetTypeFromAssociation(*symbol); + SetAttrsFromAssociation(*symbol); + } + } + PopAssociation(assocCount); } + void ConstructVisitor::Post(const parser::EndAssociateStmt &x) { - PopAssociation(); PopScope(); CheckRef(x.v); } -void ConstructVisitor::Post(const parser::Association &x) { +bool ConstructVisitor::Pre(const parser::Association &x) { + PushAssociation(); const auto &name{std::get(x.t)}; GetCurrentAssociation().name = &name; - if (auto *symbol{MakeAssocEntity()}) { - if (ExtractCoarrayRef(GetCurrentAssociation().selector.expr)) { // C1103 - Say("Selector must not be a coindexed object"_err_en_US); - } - SetTypeFromAssociation(*symbol); - SetAttrsFromAssociation(*symbol); - } - GetCurrentAssociation() = {}; // clean for further parser::Association. + return true; } bool ConstructVisitor::Pre(const parser::ChangeTeamStmt &x) { @@ -5330,14 +5336,14 @@ } } -// Make a symbol representing an associating entity from current association. +// Make a symbol for the associating entity of the current association. Symbol *ConstructVisitor::MakeAssocEntity() { Symbol *symbol{nullptr}; auto &association{GetCurrentAssociation()}; if (association.name) { symbol = &MakeSymbol(*association.name, UnknownDetails{}); if (symbol->has() && symbol->owner() == currScope()) { - Say(*association.name, // C1104 + Say(*association.name, // C1102 "The associate name '%s' is already used in this associate statement"_err_en_US); return nullptr; } @@ -5405,18 +5411,29 @@ x.u); } +// Set the current association to the nth to the last association on the +// association stack. The top of the stack is at n = 1. This allows access +// to the interior of a list of associations at the top of the stack. +void ConstructVisitor::SetCurrentAssociation(std::size_t n) { + CHECK(n > 0 && n <= associationStack_.size()); + currentAssociation_ = &associationStack_[associationStack_.size() - n]; +} + ConstructVisitor::Association &ConstructVisitor::GetCurrentAssociation() { - CHECK(!associationStack_.empty()); - return associationStack_.back(); + CHECK(currentAssociation_); + return *currentAssociation_; } void ConstructVisitor::PushAssociation() { associationStack_.emplace_back(Association{}); + currentAssociation_ = &associationStack_.back(); } -void ConstructVisitor::PopAssociation() { - CHECK(!associationStack_.empty()); - associationStack_.pop_back(); +void ConstructVisitor::PopAssociation(std::size_t count) { + CHECK(count > 0 && count <= associationStack_.size()); + associationStack_.resize(associationStack_.size() - count); + currentAssociation_ = + associationStack_.empty() ? nullptr : &associationStack_.back(); } const DeclTypeSpec &ConstructVisitor::ToDeclTypeSpec( diff --git a/flang/test/Semantics/resolve100.f90 b/flang/test/Semantics/resolve100.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/resolve100.f90 @@ -0,0 +1,14 @@ +!RUN: %f18 -fdebug-dump-symbols -fparse-only %s | FileCheck %s + +program p + ! CHECK: a size=4 offset=0: ObjectEntity type: LOGICAL(4) + ! CHECK: b size=4 offset=4: ObjectEntity type: REAL(4) + logical :: a = .false. + real :: b = 9.73 + ! CHECK: a: AssocEntity type: REAL(4) expr:b + ! CHECK: b: AssocEntity type: LOGICAL(4) expr:a + associate (b => a, a => b) + print*, a, b + end associate + print*, a, b +end