[flang-commits] [flang] 47b97d4 - [flang] Manage per-specification-part state better
peter klausler via flang-commits
flang-commits at lists.llvm.org
Wed Feb 10 17:24:03 PST 2021
Author: peter klausler
Date: 2021-02-10T17:23:53-08:00
New Revision: 47b97d4bfbe8a1245f481790aefc538aba32ad94
URL: https://github.com/llvm/llvm-project/commit/47b97d4bfbe8a1245f481790aefc538aba32ad94
DIFF: https://github.com/llvm/llvm-project/commit/47b97d4bfbe8a1245f481790aefc538aba32ad94.diff
LOG: [flang] Manage per-specification-part state better
Some state in name resolution is stored in the DeclarationVisitor
instance and processed at the end of the specification part.
This state needs to accommodate nested specification parts, namely
the ones that can be nested in a subroutine or function interface
body.
Differential Revision: https://reviews.llvm.org/D96466
Added:
flang/test/Semantics/resolve101.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 fafccc1eb74d..7e122db3150f 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -599,7 +599,26 @@ class ScopeHandler : public ImplicitRulesVisitor {
bool inExecutionPart_{false};
bool inSpecificationPart_{false};
bool inEquivalenceStmt_{false};
- std::set<SourceName> specPartForwardRefs_;
+
+ // Some information is collected from a specification part for deferred
+ // processing in DeclarationPartVisitor functions (e.g., CheckSaveStmts())
+ // that are called by ResolveNamesVisitor::FinishSpecificationPart(). Since
+ // specification parts can nest (e.g., INTERFACE bodies), the collected
+ // information that is not contained in the scope needs to be packaged
+ // and restorable.
+ struct SpecificationPartState {
+ std::set<SourceName> forwardRefs;
+ // Collect equivalence sets and process at end of specification part
+ std::vector<const std::list<parser::EquivalenceObject> *> equivalenceSets;
+ // Names of all common block objects in the scope
+ std::set<SourceName> commonBlockObjects;
+ // Info about about SAVE statements and attributes in current scope
+ struct {
+ std::optional<SourceName> saveAll; // "SAVE" without entity list
+ std::set<SourceName> entities; // names of entities with save attr
+ std::set<SourceName> commons; // names of common blocks with save attr
+ } saveInfo;
+ } specPartState_;
private:
Scope *currScope_{nullptr};
@@ -888,16 +907,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
bool sequence{false}; // is a sequence type
const Symbol *type{nullptr}; // derived type being defined
} derivedTypeInfo_;
- // Collect equivalence sets and process at end of specification part
- std::vector<const std::list<parser::EquivalenceObject> *> equivalenceSets_;
- // Names of all common block objects in the scope
- std::set<SourceName> commonBlockObjects_;
- // Info about about SAVE statements and attributes in current scope
- struct {
- std::optional<SourceName> saveAll; // "SAVE" without entity list
- std::set<SourceName> entities; // names of entities with save attr
- std::set<SourceName> commons; // names of common blocks with save attr
- } saveInfo_;
// In a ProcedureDeclarationStmt or ProcComponentDefStmt, this is
// the interface name, if any.
const parser::Name *interfaceName_{nullptr};
@@ -2223,7 +2232,7 @@ void ScopeHandler::NotePossibleBadForwardRef(const parser::Name &name) {
? name.symbol->has<HostAssocDetails>()
: name.symbol->owner().Contains(currScope())};
if (isHostAssociated) {
- specPartForwardRefs_.insert(name.source);
+ specPartState_.forwardRefs.insert(name.source);
}
}
}
@@ -2231,8 +2240,8 @@ void ScopeHandler::NotePossibleBadForwardRef(const parser::Name &name) {
std::optional<SourceName> ScopeHandler::HadForwardRef(
const Symbol &symbol) const {
- auto iter{specPartForwardRefs_.find(symbol.name())};
- if (iter != specPartForwardRefs_.end()) {
+ auto iter{specPartState_.forwardRefs.find(symbol.name())};
+ if (iter != specPartState_.forwardRefs.end()) {
return *iter;
}
return std::nullopt;
@@ -4422,7 +4431,7 @@ bool DeclarationVisitor::Pre(const parser::CommonBlockObject &) {
void DeclarationVisitor::Post(const parser::CommonBlockObject &x) {
const auto &name{std::get<parser::Name>(x.t)};
DeclareObjectEntity(name);
- auto pair{commonBlockObjects_.insert(name.source)};
+ auto pair{specPartState_.commonBlockObjects.insert(name.source)};
if (!pair.second) {
const SourceName &prev{*pair.first};
Say2(name.source, "'%s' is already in a COMMON block"_err_en_US, prev,
@@ -4434,7 +4443,7 @@ bool DeclarationVisitor::Pre(const parser::EquivalenceStmt &x) {
// save equivalence sets to be processed after specification part
if (CheckNotInBlock("EQUIVALENCE")) { // C1107
for (const std::list<parser::EquivalenceObject> &set : x.v) {
- equivalenceSets_.push_back(&set);
+ specPartState_.equivalenceSets.push_back(&set);
}
}
return false; // don't implicitly declare names yet
@@ -4443,7 +4452,7 @@ bool DeclarationVisitor::Pre(const parser::EquivalenceStmt &x) {
void DeclarationVisitor::CheckEquivalenceSets() {
EquivalenceSets equivSets{context()};
inEquivalenceStmt_ = true;
- for (const auto *set : equivalenceSets_) {
+ for (const auto *set : specPartState_.equivalenceSets) {
const auto &source{set->front().v.value().source};
if (set->size() <= 1) { // R871
Say(source, "Equivalence set must have more than one object"_err_en_US);
@@ -4465,12 +4474,12 @@ void DeclarationVisitor::CheckEquivalenceSets() {
currScope().add_equivalenceSet(std::move(set));
}
}
- equivalenceSets_.clear();
+ specPartState_.equivalenceSets.clear();
}
bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
if (x.v.empty()) {
- saveInfo_.saveAll = currStmtSource();
+ specPartState_.saveInfo.saveAll = currStmtSource();
currScope().set_hasSAVE();
} else {
for (const parser::SavedEntity &y : x.v) {
@@ -4478,7 +4487,7 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
const auto &name{std::get<parser::Name>(y.t)};
if (kind == parser::SavedEntity::Kind::Common) {
MakeCommonBlockSymbol(name);
- AddSaveName(saveInfo_.commons, name.source);
+ AddSaveName(specPartState_.saveInfo.commons, name.source);
} else {
HandleAttributeStmt(Attr::SAVE, name);
}
@@ -4488,15 +4497,15 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
}
void DeclarationVisitor::CheckSaveStmts() {
- for (const SourceName &name : saveInfo_.entities) {
+ for (const SourceName &name : specPartState_.saveInfo.entities) {
auto *symbol{FindInScope(name)};
if (!symbol) {
// error was reported
- } else if (saveInfo_.saveAll) {
+ } else if (specPartState_.saveInfo.saveAll) {
// C889 - note that pgi, ifort, xlf do not enforce this constraint
Say2(name,
"Explicit SAVE of '%s' is redundant due to global SAVE statement"_err_en_US,
- *saveInfo_.saveAll, "Global SAVE statement"_en_US);
+ *specPartState_.saveInfo.saveAll, "Global SAVE statement"_en_US);
} else if (auto msg{CheckSaveAttr(*symbol)}) {
Say(name, std::move(*msg));
context().SetError(*symbol);
@@ -4504,7 +4513,7 @@ void DeclarationVisitor::CheckSaveStmts() {
SetSaveAttr(*symbol);
}
}
- for (const SourceName &name : saveInfo_.commons) {
+ for (const SourceName &name : specPartState_.saveInfo.commons) {
if (auto *symbol{currScope().FindCommonBlock(name)}) {
auto &objects{symbol->get<CommonBlockDetails>().objects()};
if (objects.empty()) {
@@ -4524,7 +4533,7 @@ void DeclarationVisitor::CheckSaveStmts() {
}
}
}
- if (saveInfo_.saveAll) {
+ if (specPartState_.saveInfo.saveAll) {
// Apply SAVE attribute to applicable symbols
for (auto pair : currScope()) {
auto &symbol{*pair.second};
@@ -4533,7 +4542,7 @@ void DeclarationVisitor::CheckSaveStmts() {
}
}
}
- saveInfo_ = {};
+ specPartState_.saveInfo = {};
}
// If SAVE attribute can't be set on symbol, return error message.
@@ -4553,10 +4562,10 @@ std::optional<MessageFixedText> DeclarationVisitor::CheckSaveAttr(
}
}
-// Record SAVEd names in saveInfo_.entities.
+// Record SAVEd names in specPartState_.saveInfo.entities.
Attrs DeclarationVisitor::HandleSaveName(const SourceName &name, Attrs attrs) {
if (attrs.test(Attr::SAVE)) {
- AddSaveName(saveInfo_.entities, name);
+ AddSaveName(specPartState_.saveInfo.entities, name);
}
return attrs;
}
@@ -4591,7 +4600,7 @@ void DeclarationVisitor::CheckCommonBlocks() {
}
}
// check objects in common blocks
- for (const auto &name : commonBlockObjects_) {
+ for (const auto &name : specPartState_.commonBlockObjects) {
const auto *symbol{currScope().FindSymbol(name)};
if (!symbol) {
continue;
@@ -4625,7 +4634,7 @@ void DeclarationVisitor::CheckCommonBlocks() {
}
}
}
- commonBlockObjects_ = {};
+ specPartState_.commonBlockObjects = {};
}
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(const parser::Name &name) {
@@ -6136,14 +6145,14 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
const auto &[accDecls, ompDecls, compilerDirectives, useStmts, importStmts,
implicitPart, decls] = x.t;
auto flagRestorer{common::ScopedSet(inSpecificationPart_, true)};
+ auto stateRestorer{
+ common::ScopedSet(specPartState_, SpecificationPartState{})};
Walk(accDecls);
Walk(ompDecls);
Walk(compilerDirectives);
Walk(useStmts);
Walk(importStmts);
Walk(implicitPart);
- auto setRestorer{
- common::ScopedSet(specPartForwardRefs_, std::set<SourceName>{})};
for (const auto &decl : decls) {
if (const auto *spec{
std::get_if<parser::SpecificationConstruct>(&decl.u)}) {
diff --git a/flang/test/Semantics/resolve101.f90 b/flang/test/Semantics/resolve101.f90
new file mode 100644
index 000000000000..90fca2b04081
--- /dev/null
+++ b/flang/test/Semantics/resolve101.f90
@@ -0,0 +1,13 @@
+! RUN: %S/test_errors.sh %s %t %f18
+! Ensure that spurious errors do not arise from FinishSpecificationPart
+! checking on a nested specification part.
+real, save :: x
+interface
+ subroutine subr(x)
+ real, intent(in) :: x
+ ! SAVE attribute checking should not complain at the
+ ! end of this specification part about a dummy argument
+ ! having the SAVE attribute.
+ end subroutine
+end interface
+end
More information about the flang-commits
mailing list