[flang] Extract DeclarationVisitor from ResolveNamesVisitor
authorTim Keith <tkeith@nvidia.com>
Wed, 30 May 2018 21:11:45 +0000 (14:11 -0700)
committerTim Keith <tkeith@nvidia.com>
Wed, 30 May 2018 21:11:45 +0000 (14:11 -0700)
The is a refactoring to move all handling of declarations from
ResolveNamesVisitor to a new class. No function change.

Original-commit: flang-compiler/f18@2a5589ab969421b1723c63105fe6922941ec1096
Reviewed-on: https://github.com/flang-compiler/f18/pull/97
Tree-same-pre-rewrite: false

flang/lib/semantics/resolve-names.cc

index 4370c4a..f01af9a 100644 (file)
@@ -428,10 +428,51 @@ private:
   Symbol *GetSpecificFromGeneric(const parser::Name &);
 };
 
+class DeclarationVisitor : public ArraySpecVisitor,
+                           public virtual ScopeHandler {
+public:
+  using ArraySpecVisitor::Post;
+  using ArraySpecVisitor::Pre;
+
+  void Post(const parser::EntityDecl &);
+  void Post(const parser::ObjectDecl &);
+  bool Pre(const parser::AsynchronousStmt &);
+  bool Pre(const parser::ContiguousStmt &);
+  bool Pre(const parser::ExternalStmt &);
+  bool Pre(const parser::IntrinsicStmt &);
+  bool Pre(const parser::OptionalStmt &);
+  bool Pre(const parser::ProtectedStmt &);
+  bool Pre(const parser::ValueStmt &);
+  bool Pre(const parser::VolatileStmt &);
+  bool Pre(const parser::AllocatableStmt &) {
+    objectDeclAttr_ = Attr::ALLOCATABLE;
+    return true;
+  }
+  void Post(const parser::AllocatableStmt &) { objectDeclAttr_ = std::nullopt; }
+  bool Pre(const parser::TargetStmt &x) {
+    objectDeclAttr_ = Attr::TARGET;
+    return true;
+  }
+  void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
+  void Post(const parser::DimensionStmt::Declaration &);
+
+protected:
+  bool BeginDecl();
+  void EndDecl();
+
+private:
+  // The attribute corresponding to the statement containing an ObjectDecl
+  std::optional<Attr> objectDeclAttr_;
+
+  // Handle a statement that sets an attribute on a list of names.
+  bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
+  void DeclareEntity(const parser::Name &, Attrs);
+};
+
 // Walk the parse tree and resolve names to symbols.
-class ResolveNamesVisitor : public ArraySpecVisitor,
-                            public ModuleVisitor,
-                            public SubprogramVisitor {
+class ResolveNamesVisitor : public ModuleVisitor,
+                            public SubprogramVisitor,
+                            public DeclarationVisitor {
 public:
   using ArraySpecVisitor::Post;
   using ArraySpecVisitor::Pre;
@@ -443,6 +484,8 @@ public:
   using ModuleVisitor::Pre;
   using SubprogramVisitor::Post;
   using SubprogramVisitor::Pre;
+  using DeclarationVisitor::Post;
+  using DeclarationVisitor::Pre;
 
   // Default action for a parse tree node is to visit children.
   template<typename T> bool Pre(const T &) { return true; }
@@ -456,35 +499,13 @@ public:
   void Post(const parser::DataComponentDefStmt &) { EndDecl(); }
   bool Pre(const parser::TypeDeclarationStmt &) { return BeginDecl(); }
   void Post(const parser::TypeDeclarationStmt &) { EndDecl(); }
-  void Post(const parser::EntityDecl &);
-  void Post(const parser::ObjectDecl &);
   void Post(const parser::ComponentDecl &);
   bool Pre(const parser::PrefixSpec &);
-  bool Pre(const parser::AsynchronousStmt &);
-  bool Pre(const parser::ContiguousStmt &);
-  bool Pre(const parser::ExternalStmt &);
-  bool Pre(const parser::IntrinsicStmt &);
-  bool Pre(const parser::OptionalStmt &);
-  bool Pre(const parser::ProtectedStmt &);
-  bool Pre(const parser::ValueStmt &);
-  bool Pre(const parser::VolatileStmt &);
   void Post(const parser::SpecificationPart &);
   bool Pre(const parser::MainProgram &);
   void Post(const parser::EndProgramStmt &);
   void Post(const parser::Program &);
 
-  bool Pre(const parser::AllocatableStmt &) {
-    objectDeclAttr_ = Attr::ALLOCATABLE;
-    return true;
-  }
-  void Post(const parser::AllocatableStmt &) { objectDeclAttr_ = std::nullopt; }
-  bool Pre(const parser::TargetStmt &x) {
-    objectDeclAttr_ = Attr::TARGET;
-    return true;
-  }
-  void Post(const parser::TargetStmt &) { objectDeclAttr_ = std::nullopt; }
-  void Post(const parser::DimensionStmt::Declaration &);
-
   void Post(const parser::Expr &x) { CheckImplicitSymbol(GetVariableName(x)); }
   void Post(const parser::Variable &x) {
     CheckImplicitSymbol(GetVariableName(x));
@@ -493,14 +514,6 @@ public:
   void Post(const parser::ProcedureDesignator &);
 
 private:
-  // The attribute corresponding to the statement containing an ObjectDecl
-  std::optional<Attr> objectDeclAttr_;
-
-  bool BeginDecl();
-  void EndDecl();
-  // Handle a statement that sets an attribute on a list of names.
-  bool HandleAttributeStmt(Attr, const std::list<parser::Name> &);
-  void DeclareEntity(const parser::Name &, Attrs);
   const parser::Name *GetVariableName(const parser::DataRef &);
   const parser::Name *GetVariableName(const parser::Designator &);
   const parser::Name *GetVariableName(const parser::Expr &);
@@ -1539,121 +1552,57 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) {
   return nullptr;
 }
 
-// ResolveNamesVisitor implementation
-
-void ResolveNamesVisitor::Post(const parser::EntityDecl &x) {
-  // TODO: may be under StructureStmt
-  const auto &name{std::get<parser::ObjectName>(x.t)};
-  // TODO: CoarraySpec, CharLength, Initialization
-  DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
-}
+// DeclarationVisitor implementation
 
-bool ResolveNamesVisitor::BeginDecl() {
+bool DeclarationVisitor::BeginDecl() {
   BeginDeclTypeSpec();
   BeginAttrs();
   BeginArraySpec();
   return true;
 }
-void ResolveNamesVisitor::EndDecl() {
+void DeclarationVisitor::EndDecl() {
   EndDeclTypeSpec();
   EndAttrs();
   EndArraySpec();
 }
 
-bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
-  BeginDeclTypeSpec();
-  return true;
-}
-void ResolveNamesVisitor::Post(const parser::TypeParamDefStmt &x) {
-  EndDeclTypeSpec();
-  // TODO: TypeParamDefStmt
-}
-
-bool ResolveNamesVisitor::Pre(const parser::CommonBlockObject &x) {
-  BeginArraySpec();
-  return true;
-}
-void ResolveNamesVisitor::Post(const parser::CommonBlockObject &x) {
-  ClearArraySpec();
-  // TODO: CommonBlockObject
-}
-
-void ResolveNamesVisitor::Post(const parser::ComponentDecl &) {
-  ClearArraySpec();
-}
-
-bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &x) {
-  return true;  // TODO
-}
-
-bool ResolveNamesVisitor::CheckUseError(
-    const SourceName &name, const Symbol &symbol) {
-  const auto *details = symbol.detailsIf<UseErrorDetails>();
-  if (!details) {
-    return false;
-  }
-  Message &msg{Say(name, "Reference to '%s' is ambiguous"_err_en_US)};
-  for (const auto &pair : details->occurrences()) {
-    const SourceName &location{*pair.first};
-    const SourceName &moduleName{pair.second->name()};
-    msg.Attach(location,
-        MessageFormattedText{"'%s' was use-associated from module '%s'"_en_US,
-            name.ToString().data(), moduleName.ToString().data()});
-  }
-  return true;
+void DeclarationVisitor::Post(const parser::DimensionStmt::Declaration &x) {
+  const auto &name = std::get<parser::Name>(x.t);
+  DeclareEntity(name, Attrs{});
 }
 
-void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
-  if (const auto *name = std::get_if<parser::Name>(&x.u)) {
-    Symbol &symbol{MakeSymbol(name->source)};
-    if (symbol.has<UnknownDetails>()) {
-      if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL)) {
-        Say(*name,
-            "'%s' is an external procedure without the EXTERNAL"
-            " attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
-      }
-      symbol.attrs().set(Attr::EXTERNAL);
-      symbol.set_details(SubprogramDetails{});
-    } else if (CheckUseError(name->source, symbol)) {
-      // error was reported
-    } else if (!symbol.isSubprogram()) {
-      auto *details = symbol.detailsIf<EntityDetails>();
-      if (!details || !details->isArray()) {
-        Say(*name,
-            "Use of '%s' as a procedure conflicts with its declaration"_err_en_US)
-            .Attach(symbol.name(),
-                MessageFormattedText{"Declaration of '%s'"_en_US,
-                    symbol.name().ToString().data()});
-      }
-    }
-  }
+void DeclarationVisitor::Post(const parser::EntityDecl &x) {
+  // TODO: may be under StructureStmt
+  const auto &name{std::get<parser::ObjectName>(x.t)};
+  // TODO: CoarraySpec, CharLength, Initialization
+  DeclareEntity(name, attrs_ ? *attrs_ : Attrs());
 }
 
-bool ResolveNamesVisitor::Pre(const parser::AsynchronousStmt &x) {
+bool DeclarationVisitor::Pre(const parser::AsynchronousStmt &x) {
   return HandleAttributeStmt(Attr::ASYNCHRONOUS, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::ContiguousStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ContiguousStmt &x) {
   return HandleAttributeStmt(Attr::CONTIGUOUS, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::ExternalStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ExternalStmt &x) {
   return HandleAttributeStmt(Attr::EXTERNAL, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::IntrinsicStmt &x) {
+bool DeclarationVisitor::Pre(const parser::IntrinsicStmt &x) {
   return HandleAttributeStmt(Attr::INTRINSIC, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::OptionalStmt &x) {
+bool DeclarationVisitor::Pre(const parser::OptionalStmt &x) {
   return HandleAttributeStmt(Attr::OPTIONAL, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::ProtectedStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ProtectedStmt &x) {
   return HandleAttributeStmt(Attr::PROTECTED, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::ValueStmt &x) {
+bool DeclarationVisitor::Pre(const parser::ValueStmt &x) {
   return HandleAttributeStmt(Attr::VALUE, x.v);
 }
-bool ResolveNamesVisitor::Pre(const parser::VolatileStmt &x) {
+bool DeclarationVisitor::Pre(const parser::VolatileStmt &x) {
   return HandleAttributeStmt(Attr::VOLATILE, x.v);
 }
-bool ResolveNamesVisitor::HandleAttributeStmt(
+bool DeclarationVisitor::HandleAttributeStmt(
     Attr attr, const std::list<parser::Name> &names) {
   for (const auto &name : names) {
     const auto pair = CurrScope().try_emplace(name.source, Attrs{attr});
@@ -1672,18 +1621,13 @@ bool ResolveNamesVisitor::HandleAttributeStmt(
   return false;
 }
 
-void ResolveNamesVisitor::Post(const parser::ObjectDecl &x) {
+void DeclarationVisitor::Post(const parser::ObjectDecl &x) {
   CHECK(objectDeclAttr_.has_value());
   const auto &name = std::get<parser::ObjectName>(x.t);
   DeclareEntity(name, Attrs{*objectDeclAttr_});
 }
 
-void ResolveNamesVisitor::Post(const parser::DimensionStmt::Declaration &x) {
-  const auto &name = std::get<parser::Name>(x.t);
-  DeclareEntity(name, Attrs{});
-}
-
-void ResolveNamesVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
+void DeclarationVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
   Symbol &symbol{MakeSymbol(name.source, attrs)};
   // TODO: check attribute consistency
   if (symbol.has<UnknownDetails>()) {
@@ -1727,6 +1671,77 @@ void ResolveNamesVisitor::DeclareEntity(const parser::Name &name, Attrs attrs) {
   }
 }
 
+// ResolveNamesVisitor implementation
+
+bool ResolveNamesVisitor::Pre(const parser::TypeParamDefStmt &x) {
+  BeginDeclTypeSpec();
+  return true;
+}
+void ResolveNamesVisitor::Post(const parser::TypeParamDefStmt &x) {
+  EndDeclTypeSpec();
+  // TODO: TypeParamDefStmt
+}
+
+bool ResolveNamesVisitor::Pre(const parser::CommonBlockObject &x) {
+  BeginArraySpec();
+  return true;
+}
+void ResolveNamesVisitor::Post(const parser::CommonBlockObject &x) {
+  ClearArraySpec();
+  // TODO: CommonBlockObject
+}
+
+void ResolveNamesVisitor::Post(const parser::ComponentDecl &) {
+  ClearArraySpec();
+}
+
+bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &x) {
+  return true;  // TODO
+}
+
+bool ResolveNamesVisitor::CheckUseError(
+    const SourceName &name, const Symbol &symbol) {
+  const auto *details = symbol.detailsIf<UseErrorDetails>();
+  if (!details) {
+    return false;
+  }
+  Message &msg{Say(name, "Reference to '%s' is ambiguous"_err_en_US)};
+  for (const auto &pair : details->occurrences()) {
+    const SourceName &location{*pair.first};
+    const SourceName &moduleName{pair.second->name()};
+    msg.Attach(location,
+        MessageFormattedText{"'%s' was use-associated from module '%s'"_en_US,
+            name.ToString().data(), moduleName.ToString().data()});
+  }
+  return true;
+}
+
+void ResolveNamesVisitor::Post(const parser::ProcedureDesignator &x) {
+  if (const auto *name = std::get_if<parser::Name>(&x.u)) {
+    Symbol &symbol{MakeSymbol(name->source)};
+    if (symbol.has<UnknownDetails>()) {
+      if (isImplicitNoneExternal() && !symbol.attrs().test(Attr::EXTERNAL)) {
+        Say(*name,
+            "'%s' is an external procedure without the EXTERNAL"
+            " attribute in a scope with IMPLICIT NONE(EXTERNAL)"_err_en_US);
+      }
+      symbol.attrs().set(Attr::EXTERNAL);
+      symbol.set_details(SubprogramDetails{});
+    } else if (CheckUseError(name->source, symbol)) {
+      // error was reported
+    } else if (!symbol.isSubprogram()) {
+      auto *details = symbol.detailsIf<EntityDetails>();
+      if (!details || !details->isArray()) {
+        Say(*name,
+            "Use of '%s' as a procedure conflicts with its declaration"_err_en_US)
+            .Attach(symbol.name(),
+                MessageFormattedText{"Declaration of '%s'"_en_US,
+                    symbol.name().ToString().data()});
+      }
+    }
+  }
+}
+
 bool ModuleVisitor::Pre(const parser::AccessStmt &x) {
   Attr accessAttr = AccessSpecToAttr(std::get<parser::AccessSpec>(x.t));
   if (CurrScope().kind() != Scope::Kind::Module) {