Skip to content

Commit ff3b51b

Browse files
committed
[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
1 parent e8aec76 commit ff3b51b

File tree

2 files changed

+54
-23
lines changed

2 files changed

+54
-23
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,9 +1010,9 @@ class ConstructVisitor : public virtual DeclarationVisitor {
10101010
bool Pre(const parser::BlockStmt &);
10111011
bool Pre(const parser::EndBlockStmt &);
10121012
void Post(const parser::Selector &);
1013-
bool Pre(const parser::AssociateStmt &);
1013+
void Post(const parser::AssociateStmt &);
10141014
void Post(const parser::EndAssociateStmt &);
1015-
void Post(const parser::Association &);
1015+
bool Pre(const parser::Association &);
10161016
void Post(const parser::SelectTypeStmt &);
10171017
void Post(const parser::SelectRankStmt &);
10181018
bool Pre(const parser::SelectTypeConstruct &);
@@ -1081,6 +1081,7 @@ class ConstructVisitor : public virtual DeclarationVisitor {
10811081
Selector selector;
10821082
};
10831083
std::vector<Association> associationStack_;
1084+
Association *currentAssociation_{nullptr};
10841085

10851086
template <typename T> bool CheckDef(const T &t) {
10861087
return CheckDef(std::get<std::optional<parser::Name>>(t));
@@ -1098,9 +1099,10 @@ class ConstructVisitor : public virtual DeclarationVisitor {
10981099
void SetAttrsFromAssociation(Symbol &);
10991100
Selector ResolveSelector(const parser::Selector &);
11001101
void ResolveIndexName(const parser::ConcurrentControl &control);
1102+
void SetCurrentAssociation(std::size_t n);
11011103
Association &GetCurrentAssociation();
11021104
void PushAssociation();
1103-
void PopAssociation();
1105+
void PopAssociation(std::size_t count = 1);
11041106
};
11051107

11061108
// Create scopes for OpenACC constructs
@@ -5153,29 +5155,33 @@ void ConstructVisitor::Post(const parser::Selector &x) {
51535155
GetCurrentAssociation().selector = ResolveSelector(x);
51545156
}
51555157

5156-
bool ConstructVisitor::Pre(const parser::AssociateStmt &x) {
5158+
void ConstructVisitor::Post(const parser::AssociateStmt &x) {
51575159
CheckDef(x.t);
51585160
PushScope(Scope::Kind::Block, nullptr);
5159-
PushAssociation();
5160-
return true;
5161+
const auto assocCount{std::get<std::list<parser::Association>>(x.t).size()};
5162+
for (auto nthLastAssoc{assocCount}; nthLastAssoc > 0; --nthLastAssoc) {
5163+
SetCurrentAssociation(nthLastAssoc);
5164+
if (auto *symbol{MakeAssocEntity()}) {
5165+
if (ExtractCoarrayRef(GetCurrentAssociation().selector.expr)) { // C1103
5166+
Say("Selector must not be a coindexed object"_err_en_US);
5167+
}
5168+
SetTypeFromAssociation(*symbol);
5169+
SetAttrsFromAssociation(*symbol);
5170+
}
5171+
}
5172+
PopAssociation(assocCount);
51615173
}
5174+
51625175
void ConstructVisitor::Post(const parser::EndAssociateStmt &x) {
5163-
PopAssociation();
51645176
PopScope();
51655177
CheckRef(x.v);
51665178
}
51675179

5168-
void ConstructVisitor::Post(const parser::Association &x) {
5180+
bool ConstructVisitor::Pre(const parser::Association &x) {
5181+
PushAssociation();
51695182
const auto &name{std::get<parser::Name>(x.t)};
51705183
GetCurrentAssociation().name = &name;
5171-
if (auto *symbol{MakeAssocEntity()}) {
5172-
if (ExtractCoarrayRef(GetCurrentAssociation().selector.expr)) { // C1103
5173-
Say("Selector must not be a coindexed object"_err_en_US);
5174-
}
5175-
SetTypeFromAssociation(*symbol);
5176-
SetAttrsFromAssociation(*symbol);
5177-
}
5178-
GetCurrentAssociation() = {}; // clean for further parser::Association.
5184+
return true;
51795185
}
51805186

51815187
bool ConstructVisitor::Pre(const parser::ChangeTeamStmt &x) {
@@ -5330,14 +5336,14 @@ void ConstructVisitor::CheckRef(const std::optional<parser::Name> &x) {
53305336
}
53315337
}
53325338

5333-
// Make a symbol representing an associating entity from current association.
5339+
// Make a symbol for the associating entity of the current association.
53345340
Symbol *ConstructVisitor::MakeAssocEntity() {
53355341
Symbol *symbol{nullptr};
53365342
auto &association{GetCurrentAssociation()};
53375343
if (association.name) {
53385344
symbol = &MakeSymbol(*association.name, UnknownDetails{});
53395345
if (symbol->has<AssocEntityDetails>() && symbol->owner() == currScope()) {
5340-
Say(*association.name, // C1104
5346+
Say(*association.name, // C1102
53415347
"The associate name '%s' is already used in this associate statement"_err_en_US);
53425348
return nullptr;
53435349
}
@@ -5405,18 +5411,29 @@ ConstructVisitor::Selector ConstructVisitor::ResolveSelector(
54055411
x.u);
54065412
}
54075413

5414+
// Set the current association to the nth to the last association on the
5415+
// association stack. The top of the stack is at n = 1. This allows access
5416+
// to the interior of a list of associations at the top of the stack.
5417+
void ConstructVisitor::SetCurrentAssociation(std::size_t n) {
5418+
CHECK(n > 0 && n <= associationStack_.size());
5419+
currentAssociation_ = &associationStack_[associationStack_.size() - n];
5420+
}
5421+
54085422
ConstructVisitor::Association &ConstructVisitor::GetCurrentAssociation() {
5409-
CHECK(!associationStack_.empty());
5410-
return associationStack_.back();
5423+
CHECK(currentAssociation_);
5424+
return *currentAssociation_;
54115425
}
54125426

54135427
void ConstructVisitor::PushAssociation() {
54145428
associationStack_.emplace_back(Association{});
5429+
currentAssociation_ = &associationStack_.back();
54155430
}
54165431

5417-
void ConstructVisitor::PopAssociation() {
5418-
CHECK(!associationStack_.empty());
5419-
associationStack_.pop_back();
5432+
void ConstructVisitor::PopAssociation(std::size_t count) {
5433+
CHECK(count > 0 && count <= associationStack_.size());
5434+
associationStack_.resize(associationStack_.size() - count);
5435+
currentAssociation_ =
5436+
associationStack_.empty() ? nullptr : &associationStack_.back();
54205437
}
54215438

54225439
const DeclTypeSpec &ConstructVisitor::ToDeclTypeSpec(

flang/test/Semantics/resolve100.f90

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
!RUN: %f18 -fdebug-dump-symbols -fparse-only %s | FileCheck %s
2+
3+
program p
4+
! CHECK: a size=4 offset=0: ObjectEntity type: LOGICAL(4)
5+
! CHECK: b size=4 offset=4: ObjectEntity type: REAL(4)
6+
logical :: a = .false.
7+
real :: b = 9.73
8+
! CHECK: a: AssocEntity type: REAL(4) expr:b
9+
! CHECK: b: AssocEntity type: LOGICAL(4) expr:a
10+
associate (b => a, a => b)
11+
print*, a, b
12+
end associate
13+
print*, a, b
14+
end

0 commit comments

Comments
 (0)