[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