[flang-commits] [flang] ff3b51b - [flang] Fix ASSOCIATE statement name resolution
peter klausler via flang-commits
flang-commits at lists.llvm.org
Wed Jan 20 11:18:38 PST 2021
Author: peter klausler
Date: 2021-01-20T11:18:27-08:00
New Revision: ff3b51b0549343b6ef7d718e036116d5b502458c
URL: https://github.com/llvm/llvm-project/commit/ff3b51b0549343b6ef7d718e036116d5b502458c
DIFF: https://github.com/llvm/llvm-project/commit/ff3b51b0549343b6ef7d718e036116d5b502458c.diff
LOG: [flang] Fix ASSOCIATE statement name resolution
F18 Clause 19.4p9 says:
The associate names of an ASSOCIATE construct have the scope of the
block.
Clause 11.3.1p1 says the ASSOCIATE statement is not itself in the block:
R1102 associate-construct is: associate-stmt block end-associate-stmt
Associate statement associations are currently fully processed from left
to right, incorrectly interposing associating entities earlier in the
list on same-named entities in the host scope.
1 program p
2 logical :: a = .false.
3 real :: b = 9.73
4 associate (b => a, a => b)
5 print*, a, b
6 end associate
7 print*, a, b
8 end
Associating names 'a' and 'b' at line 4 in this code are now both
aliased to logical host entity 'a' at line 2. This happens because the
reference to 'b' in the second association incorrectly resolves 'b' to
the entity in line 4 (already associated to 'a' at line 2), rather than
the 'b' at line 3. With bridge code to process these associations,
f18 output is:
F F
F 9.73
It should be:
9.73 F
F 9.73
To fix this, names in right-hand side selector variables/expressions
must all be resolved before any left-hand side entities are resolved.
This is done by maintaining a stack of lists of associations, rather
than a stack of associations. Each ASSOCIATE statement's list of
assocations is then visited once for right-hand side processing, and
once for left-hand side processing.
Note that other construct associations do not have this problem.
SELECT RANK and SELECT TYPE each have a single assocation, not a list.
Constraint C1113 prohibits the right-hand side of a CHANGE TEAM
association from referencing any left-hand side entity.
Differential Revision: https://reviews.llvm.org/D95010
Added:
flang/test/Semantics/resolve100.f90
Modified:
flang/lib/Semantics/resolve-names.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 5d9ee35b79b3..3bc9a85cbf41 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1010,9 +1010,9 @@ class ConstructVisitor : public virtual DeclarationVisitor {
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 @@ class ConstructVisitor : public virtual DeclarationVisitor {
Selector selector;
};
std::vector<Association> associationStack_;
+ Association *currentAssociation_{nullptr};
template <typename T> bool CheckDef(const T &t) {
return CheckDef(std::get<std::optional<parser::Name>>(t));
@@ -1098,9 +1099,10 @@ class ConstructVisitor : public virtual DeclarationVisitor {
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 @@ void ConstructVisitor::Post(const parser::Selector &x) {
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<std::list<parser::Association>>(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<parser::Name>(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 @@ void ConstructVisitor::CheckRef(const std::optional<parser::Name> &x) {
}
}
-// 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<AssocEntityDetails>() && 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 @@ ConstructVisitor::Selector ConstructVisitor::ResolveSelector(
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
index 000000000000..1e84be24c5f2
--- /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
More information about the flang-commits
mailing list