[flang] Handle undeclared names in EQUIVALENCE statements

Names in EQUIVALENCE statements are only allowed to indicate local
objects as per 19.5.1.4, paragraph 2, item (10).  Thus, a name appearing
in an EQUIVALENCE statement with no corresponding declaration in the
same scope is an implicit declaration of the name.  If that scope
contains an IMPLICIT NONE, it's an error.

I implemented this by adding a state variable to ScopeHandler to
indicate if we're resolving the names in an EQUIVALENCE statement and
then checked this state when resolving names.  I also added a test to
the existing tests for EQUIVALENCE statements.

Differential Revision: https://reviews.llvm.org/D93345
This commit is contained in:
Peter Steinfeld 2020-12-15 14:44:22 -08:00
parent 869f8363c4
commit 4e90cad6a6
2 changed files with 29 additions and 4 deletions

View File

@ -597,6 +597,7 @@ protected:
bool inExecutionPart_{false};
bool inSpecificationPart_{false};
bool inEquivalenceStmt_{false};
std::set<SourceName> specPartForwardRefs_;
private:
@ -2021,7 +2022,11 @@ Symbol *ScopeHandler::FindSymbol(const Scope &scope, const parser::Name &name) {
}
return FindSymbol(scope.parent(), name);
} else {
return Resolve(name, scope.FindSymbol(name.source));
// In EQUIVALENCE statements only resolve names in the local scope, see
// 19.5.1.4, paragraph 2, item (10)
return Resolve(name,
inEquivalenceStmt_ ? FindInScope(scope, name)
: scope.FindSymbol(name.source));
}
}
@ -4347,15 +4352,17 @@ void DeclarationVisitor::Post(const parser::CommonBlockObject &x) {
bool DeclarationVisitor::Pre(const parser::EquivalenceStmt &x) {
// save equivalence sets to be processed after specification part
CheckNotInBlock("EQUIVALENCE"); // C1107
for (const std::list<parser::EquivalenceObject> &set : x.v) {
equivalenceSets_.push_back(&set);
if (CheckNotInBlock("EQUIVALENCE")) { // C1107
for (const std::list<parser::EquivalenceObject> &set : x.v) {
equivalenceSets_.push_back(&set);
}
}
return false; // don't implicitly declare names yet
}
void DeclarationVisitor::CheckEquivalenceSets() {
EquivalenceSets equivSets{context()};
inEquivalenceStmt_ = true;
for (const auto *set : equivalenceSets_) {
const auto &source{set->front().v.value().source};
if (set->size() <= 1) { // R871
@ -4372,6 +4379,7 @@ void DeclarationVisitor::CheckEquivalenceSets() {
}
equivSets.FinishSet(source);
}
inEquivalenceStmt_ = false;
for (auto &set : equivSets.sets()) {
if (!set.empty()) {
currScope().add_equivalenceSet(std::move(set));

View File

@ -197,3 +197,20 @@ subroutine s16
end interface
end subroutine s16
module m17
real :: dupName
contains
real function f17a()
implicit none
real :: y
!ERROR: No explicit type declared for 'dupname'
equivalence (dupName, y)
end function f17a
real function f17b()
real :: y
! The following implicitly declares an object called "dupName" local to
! the function f17b(). OK since there's no "implicit none
equivalence (dupName, y)
end function f17b
end module m17